java多线程三种实现方式和线程池使用详解
1、多线程的三种实现方式
1.1、继承Thread类
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "主线程");
new Thread("thread实现多线程") {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "子线程");
}
}.start();
}
1.2、实现Runnable接口
public static void main(String[] args) {
new Thread(
new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "2");
}
}, "runnable实现多线程").start();
}
1.3、实现Callable接口
与使用Runnable相比, Callable功能更强大些
- 相比run()方法,可以有返回值
- 方法可以抛出异常
- 支持泛型的返回值
- 需要借助FutureTask类,比如获取返回结果
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "主线程");
Callable<Integer> callable = new Callable<Integer>() {
private Integer sum=0;
@Override
public Integer call() throws Exception {
for(int i = 0;i<=100;i++){
if(i % 2 == 0){
sum += i;
Thread.sleep(100);
}
}
return sum;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
try {
//get返回值即为FutureTask构造器参数callable实现类重写的call的返回值
//get方法是阻塞的,直到拿到线程的执行结果
Integer sum = futureTask.get();
System.out.println(Thread.currentThread().getName()+":"+sum);
}catch (Exception e){
e.printStackTrace();
}
}
2、线程安全问题
2.1、卖车票案例
下面代码案例中,会出现多个线程卖同一张票问题,也会出现卖票出现负数问题,这就是使用多线程时,发生了线程安全问题。
public static void main(String[] args) {
/**
* 创建一个Runnable共享ticket
*/
Runnable runnable = new Runnable() {
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "--->正在卖第" + ticket-- + "张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
Thread thread3 = new Thread(runnable, "线程3");
thread1.start();
thread2.start();
thread3.start();
}
2.2、解决线程安全
同步代码块
其中,obj 称为同步监视器,也就是锁,原理是:当线程开始执行同步代码块前,必须先获得对同步代码块的锁定。并且任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完成后,该线程会释放对该同步监视器的锁定。
其中的锁,在非静态方法中可为this,在静态方法中为当前类(类名.class)。
synchronized(obj){
//需要被同步的代码块
}
//已经可以正常卖票了
public