2021-3-22 Java多线程
并行与并发
并行:指两个或多个事件同时发生 如:边打电话边吃饭
并发:指两个或多个事件交替执行 如:吃一口饭,喝一口汤,再吃一口饭
线程与进程
进程:一个内存中运行的应用程序,数据存放空间是独立的,至少有一个线程。
线程:进程中的执行单元,堆空间是共享的,栈空间是独立的,线程的资源消耗比进程的小的多。
一个进程中可以有多个线程,这个程序被称为多线程程序。
多线程的随机性:一个进程中的多个线程是并发运行的,执行顺序由cpu随机执行,无法干涉。
线程创建的过程
创建一个类继承Thread,并且重写thread当中的run方法
在主方法中创建对象,用start方法调用该对象。
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(getName()+i);
}
}
}
/*创建线程Thread*/
MyThread myThread = new MyThread();
myThread.start();
使用Runnable接口方式创建线程
创建一个类实现Runnable接口,并且重写当中的run方法
在主方法中创建对象,并将该对象传入新建的Thread对象当中。
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
//创建runnable线程
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
好处:可以继续继承别的类,实现其他接口,任务可以线程共享
使用匿名内部类创建
//使用匿名内部类创建
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
});
thread1.run();
线程安全
案例:卖票时多线程共享数据,造成了资源抢夺,出现重复卖票的情况
解决方法:对共享资源进行加锁处理
加锁的方式分为两种,一种是synchronized加锁,另一种是lock加锁
public class TicketTestImpl implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
//对资源信息进行加锁处理
synchronized (new Object()){//需要传入一个唯一的值,类似object,this
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖了:"+ticket);
ticket--;
}else{
System.exit(0);
}
}
}
}
}
或者可以将锁对象放到方法前,(相当于synchronized传入了this,静态对象则传入当前对象的字节码)
public synchronized void TicketMethod(){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖了:"+ticket);
ticket--;
}else{
System.exit(0);
}
}
Lock方式加锁
Lock l = new ReentrantLock();
@Override
public void run() {
while(true){
//加锁
l.lock();
TicketMethod();
//解锁
l.unlock();
}
}
线程状态
线程等待Thread.wait(),随机唤醒一个线程Thread.notify(),唤醒所有线程Thread.notifyall()
synchronized传入的锁对象必须是相同的
Object obj = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj){
System.out.println("顾客:老板我要吃饺子");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("顾客:饺子真好吃");
}
}
}){
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj){
try {
Thread.sleep(3000);
System.out.println("老板:饺子做好了");
obj.notify();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
线程池
public static void main(String[] args) {
//1.使用线程池工厂Executors提供的静态方法newFixedThreadPool
// 生产一个制定线程数量的线程池
ExecutorService ex = Executors.newFixedThreadPool(2);
//2.调用线程池ExecutorService中的方法submit,传递线程任务,执行线程任务
// 相当于new Thread(new Runnable(){}).start();
ex.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程任务1执行了!");
}
});
ex.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程任务2执行了!");
}
});
ex.shutdown();//销毁线程
}