java-----多线程
多线程基本概念
1.什么是多线程?
有了多线程,我们就可以让程序同时做多件事情
2.多线程的作用?
提高效率,让cpu在多个程序之间切换
3.多线程的应用场景?
只要你想让多个事情同时运行就需要多线程
比如:软件中的耗时操作、所有聊天软件、所有的服务器
并发和并行
1.并发:在同一时刻,有多个指令在单个CPU上交替执行
2.并行:在同一时刻,有多个指令在多个CPU上同时执行
多线程三种实现方式
1.继承Thread类的方式实现
将一个类声明为Thread
的子类。 这个子类应该重写Thread类的方法run。
代码块演示:
public class MyThread extends Thread{ //子类调用父类的getName方法 @Override public void run() {//t1 t2都会执行当前 //线程要执行的 for (int i = 0; i < 20; i++) { Thread thread = Thread.currentThread(); System.out.println(getName()+"helloworld"); } } }测试类main方法:
public class demo1{ public static void main(String[] args) { //1.自己定义一个类继承Thread //2.重写run方法 //3.创建子类对象,并启动线程 MyThread t1=new MyThread(); MyThread t2=new MyThread(); t1.setName("线程1"); t2.setName("线程2"); //启动线程 t1.start(); t2.start(); } } 运行结果:仅仅是一部分运行结果,可以看出线程1和2是交替执行的
2.实现Runnable接口的方式进行实现
创建一个线程是声明实现类Runnable
接口。 那个类然后实现了run
方法。 然后可以分配类的实例,在创建Thread
时作为参数传递,并启动。
代码演示:
public class MyRun implements Runnable{ //自强 @Override public void run() { for (int i = 0; i < 100; i++) { Thread thread = Thread.currentThread();//获取当前线程 System.out.println(thread.getName()+"nihao"); } } }
public class demo2 { public static void main(String[] args) { //1.自己定义一个类实现Runnable接口 //2.重写里面的run方法 //3.创建自己类的对象 //4.创建一个Thread对象,并开启线程 MyRun mr=new MyRun(); Thread t1=new Thread(mr); Thread t2=new Thread(mr); t1.setName("线程1"); t1.start(); t2.setName("线程2"); t2.start(); } }
3.利用Callable接口和Future接口方式实现
可以获得多线程执行的返回结果
import java.util.concurrent.Callable; public class MyCallable implements Callable<Integer>{ @Override public Integer call() throws Exception { int sum=0; for (int i = 0; i <=100; i++) { sum+=i; } return sum; } }public class demo3 { public static void main(String[] args) throws ExecutionException, InterruptedException { //可以获取多线程运行的返回结果 //1.创建MyCallable对象 表示多线程要执行人物 MyCallable mc=new MyCallable(); //创建FutureTask 管理结果 FutureTask<Integer> ft=new FutureTask<>(mc); Thread t1=new Thread(ft); t1.start(); Integer result=ft.get(); System.out.println(result); } }运行结果:
5050
多线程中常见成员方法
部分代码演示:
线程优先级:
抢占式调度:随机性、优先级越大,线程抢占概率越大
public class demo11 { public static void main(String[] args) { MyThread4 t1=new MyThread4("坦克"); MyThread4 t2=new MyThread4("飞机"); System.out.println(t1.getPriority()); System.out.println(t2.getPriority()); t1.setPriority(1); t2.setPriority(10);//最大优先级为10 t1.start(); t2.start(); } } public class MyThread4 extends Thread{ public MyThread4(String name){ super(name); } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+"-"+i); } } } 执行结果: 飞机和坦克都可能先执行完毕,优先级不是绝对只是概率问题守护线程:
当非守护线程执行完毕后,守护线程就会结束。
应用场景:
比如qq两天,其中一个要发送文件给另一个人,聊天是线程1,传输文件时线程2,当线程1执行结束后,那么线程2也没有存在的必要了,线程2可以设置为守护线程。
线程生命周期
线程安全问题
应用场景:
某电影院目前正在上映国产大片,共有100张票,而它又3个窗口买票,设计一个程序模拟电影院买票。
public class demo7 { public static void main(String[] args) { ThreadMyRun tmr=new ThreadMyRun(); Thread t1=new Thread(tmr); Thread t2=new Thread(tmr); Thread t3=new Thread(tmr); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); } }运行结果:会发现出现重复的票,也会有超出范围的票
原因:
1.打印会出现重复的票:
三个线程,第一个线程执行完之后,会睡眠10毫秒,然后线程2这时候会抢占进程,然后睡眠10毫秒,然后第三个线程执行完之后,会睡眠10毫秒,一直在ticket++,最后都输出卖出ticket张票,所以这里出现了打印出现重复的票.
2.超出范围的票
当打印到99的时候,三个线程出现上面的情况,因为一直没有打印完,ticket++了三次,所以打印完之后才会出现再去判断票是否还满足100以内.打印了102、102、102
怎么解决这个问题?
当有线程在代码中执行时,就把它锁起来,只有当前线程执行完之后,其它线程才能进入,把共享数据的这段代码锁起来
同步代码块
把操作共享数据的代码锁起来
格式:
synchronized(锁){
操作共享数据的代码。
}
特点1:锁默认打开,有一个线程进去了,锁自动关闭
特点2:里面的代码全部执行完毕,线程出来,锁自动打开
public class ThreadMyRun implements Runnable{ int ticket=0;//这种创建方法 因为ThreadMyRun是传递的参数 只会创建一次 @Override public void run() { while(true){ try { if (method()) break; } catch (InterruptedException e) { e.printStackTrace(); } } } private boolean method() throws InterruptedException { synchronized (ThreadMyRun.class){ //1.不能写在while循环的外面,因为如果放在外面,只有第一个抢到运行优先权线程执行完while之后,才能第二个线程进入同步代码块 2.同步代码块里的锁必须时唯一的,这里用的字节码文件,如果用几个线程用不同的锁,那么锁的意义也就没了 if(ticket==100){ return true; } else{ Thread.sleep(100); ticket++; System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"票"); } } return false; } }运行结果:可以看到正常运行
lock锁
提供了获得锁和释放锁的方法:lock()、unlock()
public class LockDemo extends Thread{ static int ticket=0; static Lock lock=new ReentrantLock();//因为Lock是接口,需要创建实现类对象 @Override public void run() { lock.lock();//加锁 while(true){ if(ticket==100){ break; } else{ try { Thread.sleep(1000); ticket++; System.out.println(getName()+"正在卖第"+ticket+"张票"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock();//执行完毕之后释放锁 } } } } }
死锁
死锁是一种常见的问题,它发生在多个线程相互等待对方释放资源时,导致它们都无法继续执行。
一般锁的嵌套会出现这种问题。
生产者消费者问题
代码模拟:
public class Cook extends Thread{ @Override public void run() { while(true){ synchronized (Desk.lock){ if(Desk.count==0){ break; } else{ if(Desk.foodFlag==1){ try { Desk.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else{ System.out.println("厨师又做了一碗,还有"); Desk.foodFlag=1; Desk.lock.notifyAll();//等待消费者 } } } } } }
public class Foodie extends Thread{ @Override public void run() { /* * 1.循环 * 2.同步代码块 * 3.共享数据是否到了末尾 到了末尾 * 4.未到末尾 * */ while(true){ synchronized (Desk.lock){ if(Desk.count==0){ break; } else{ if(Desk.foodFlag==0){//没有面条 try { Desk.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else{ Desk.count--; System.out.println("吃过正在吃面条,还能再吃"+Desk.count+"碗"); Desk.lock.notifyAll();//唤醒的是厨师 Desk.foodFlag=0; } } } } } }
package ThreadDemo; public class Desk { /* 控制生产者消费者的执行 */ //是否有面条 0有 1没有 public static int foodFlag=0; //总个数 public static int count=10; //上锁 public static Object lock=new Object(); }
public class demo9 { public static void main(String[] args) { Cook c=new Cook(); Foodie f=new Foodie(); c.setName("厨师"); c.setName("吃货"); c.start(); f.start(); } } 运行结果:
生产者消费者阻塞队列实现
public class Cook2 extends Thread{ ArrayBlockingQueue<String> queue; public Cook2(ArrayBlockingQueue<String>queue){ this.queue=queue; } @Override public void run() { while(true){ try { queue.put("面条"); System.out.println("厨师放一碗面条");//这个是锁的外面 } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Food2 extends Thread{ ArrayBlockingQueue<String> queue; public Food2(ArrayBlockingQueue<String>queue){ this.queue=queue; } @Override public void run() { while(true){ try { String food=queue.take(); System.out.println(food); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class demo10 { public static void main(String[] args) { ArrayBlockingQueue<String>queue=new ArrayBlockingQueue<>(1);//创建容量为1的阻塞队列 Food2 food2=new Food2(queue); Cook2 cook2=new Cook2(queue); food2.start(); cook2.start(); } }
线程6种状态
原文地址:https://blog.csdn.net/qq_44766305/article/details/143033808
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!