多线程
一、多线程的创建
第一种:extends Thread类
第二种:implements Runnable接口
第三种:实现callable接口
第四种:使用线程池
案例:
package com.xyz.java2;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/*创建多线程的方式:
1.继承Thread
2.实现Runnable
3.实现Callable
*/
class MyThread01 extends Thread {
@Override
public void run() {
System.out.println("-----MyThread01");
}
}
class MyThread02 implements Runnable {
public void run() {
System.out.println("-----MyThread02");
}
}
class MyThread03 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("-----MyThread03");
return 200;
}
}
public class ThreadNew {
public static void main(String[] args) {
new MyThread01().start();
new Thread(new MyThread02()).start();
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread03());
new Thread(futureTask).start();
try {
Integer value = futureTask.get();
System.out.println(value);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
package com.xyz.interview;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//创建并使用多线程的第四种方法:使用线程池
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class ThreadPool {
public static void main(String[] args) {
// 1.调用Executors的newFixedThreadPool(),返回指定线程数量的ExecutorService
ExecutorService pool = Executors.newFixedThreadPool(10);
// 2.将Runnable实现类的对象作为形参传递给ExecutorService的submit()方法中,开启线程
// 并执行相关的run()
pool.execute(new MyThread());
pool.execute(new MyThread());
pool.execute(new MyThread());
// 3.结束线程的使用
pool.shutdown();
}
}
二、线程同步:
1.编写synchronized同步代码块
2.编写synchronized同步方法
3.使用lock()和unlock()方法
synchronized:
1.任意对象都可以作为同步锁。 所有对象都自动含有单一的锁(监视器)
2.同步方法的锁:静态方法(类名.class) 、 非静态方法(this)
3.同步代码块:自己指定, 很多时候也是指定为this或类名.class
需要注意的是:
1.必须确保使用同一个资源的多个线程共用一把锁, 这个非常重要, 否则就
无法保证共享资源的安全
2.一个线程类中的所有静态方法共用同一把锁(类名.class) , 所有非静态方
法共用同一把锁(this) , 同步代码块(指定需谨慎)
lock()和unlock()
class A{
private final ReentrantLock lock = new ReenTrantLock();
public void m(){
lock.lock();
try{
//保证线程安全的代码;
}
finally{
lock.unlock();
}
}
}
synchronized 与 Lock 的对比
1.Lock是显式锁(手动开启和关闭锁,别忘记关闭锁), synchronized是
隐式锁,出了作用域自动释放
2.Lock只有代码块锁, synchronized有代码块锁和方法锁
3.使用Lock锁, JVM将花费较少的时间来调度线程,性能更好。并且具有
更好的扩展性(提供更多的子类)
三、线程通信中的常用方法
wait()
效果:调用此方法后,当前线程将释放对象监控权 ,使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify(或notifyAll) 为止,
使用条件:当前线程必须具有对该对象的监控权(加锁)
notify()/notifyAll()
功能:唤醒等待该对象监控权的一个/所有线程
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
class Clerk { // 售货员
private int product = 0;
public synchronized void addProduct() {
if (product >= 20) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
product++;
System.out.println("生产者生产了第" + product + "个产品");
notifyAll();
}
}
public synchronized void getProduct() {
if (this.product <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("消费者取走了第" +product + "个产品");
product--;
notifyAll();
}
}
}
class Productor implements Runnable { // 生产者
Clerk clerk;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
public void run() {
System.out.println("生产者开始生产产品");
while (true) {
try {
Thread.sleep((int) Math.random() * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.addProduct();
}
}
}
class Consumer implements Runnable { // 消费者
Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
public void run() {
System.out.println("消费者开始取走产品");
while (true) {
try {
Thread.sleep((int) Math.random() * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.getProduct();
}
}
}
public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Thread productorThread = new Thread(new Productor(clerk));
Thread consumerThread = new Thread(new Consumer(clerk));
productorThread.start();
consumerThread.start();
}
}