600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Java封神路之多线程(第二篇) 从把握整体架构到具体演示 快速掌握多线程机制

Java封神路之多线程(第二篇) 从把握整体架构到具体演示 快速掌握多线程机制

时间:2019-07-31 11:46:16

相关推荐

Java封神路之多线程(第二篇) 从把握整体架构到具体演示 快速掌握多线程机制

目录

一、和线程调度有关的方法

二、线程同步机制

三、练习题

四、死锁🔒

五、守护线程和定时器

六、实现线程的第三种方式 ,实现Callable接口

七、Object类中的wait和notify方法—生产者和消费者模式

一、和线程调度有关的方法

1.void setPriority(int newPriority) 设置线程的优先级

2.int getPriority() 获取线程优先级

package com.java.javase.Thread;public class ThreadTest08 {public static void main(String[] args) {Thread currentThread=Thread.currentThread();System.out.println(currentThread.getName()+"线程的默认优先级是:"+currentThread.getPriority());Thread t=new Thread(new MyThread8());t.setName("t");t.start();}}class MyThread8 implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"线程的默认优先级是:"+Thread.currentThread().getPriority());}}

输出结果:

main线程的默认优先级是:5

t线程的默认优先级是:5

3.Thread.yield() 当前线程暂停一下

package com.java.javase.Thread;public class ThreadTest {public static void main(String[] args) {/*** 让位,让当前线程暂停,回到就绪状态,让给其他线程* 静态方法:Thread.yield();*/Thread t=new Thread(new MyRunable());t.setName("t");t.start();for(int i=0;i<100;i++){System.out.println(Thread.currentThread().getName()+"--->"+i);}}}class MyRunable implements Runnable{@Overridepublic void run() {for(int i=0;i<100;i++){// 每10个让位一次if(i%10==0){Thread.yield(); // 当前线程暂停一下,让给主线程}System.out.println(Thread.currentThread().getName()+"--->"+i);}}}

4.void join() 合并线程

package com.java.javase.Thread;public class ThreadTest {public static void main(String[] args) throws InterruptedException {System.out.println("main begin");Thread t=new Thread(new MyRunable());t.setName("t");t.start();// 合并线程t.join(); // t合并到当前线程中,当前线程受到阻塞,t线程执行直到结束,栈之间进行了协调System.out.println("main over");}}class MyRunable implements Runnable{@Overridepublic void run() {for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName()+"--->"+i);}}}

输出结果:

main begin

t--->0

t--->1

t--->2

t--->3

t--->4

main over

二、线程同步机制

不使用线程同步机制下—模拟两个线程对同一个账户取款

账户类

package com.java.javase.ThreadSafe;/**银行账户*/public class Account {private String no;private double balance;public Account() {}public Account(String no, double balance) {this.no = no;this.balance = balance;}public String getNo() {return no;}public void setNo(String no) {this.no = no;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}// 提供一个取款的方法public void withDraw(double money){// 未使用线程同步机制// t1和t2并发这个方法(t1和t2是两个栈,两个栈操作堆中同一个对象)double before=this.getBalance();double after=before-money;this.setBalance(after);}}

线程类

package com.java.javase.ThreadSafe;public class AccountThread extends Thread {// 两个线程必须共享同一个账户对象private Account act;public AccountThread(Account act){this.act=act;}@Overridepublic void run() {double money=5000;act.withDraw(money);System.out.println(Thread.currentThread().getName()+"对001账户取款成功 "+"剩余余额:"+act.getBalance() );}}

测试类

package com.java.javase.ThreadSafe;public class Test {public static void main(String[] args) {// 相当于同一张银行卡,属性有卡的账号和余额Account act=new Account("001",10000);// 两个栈操作堆中同一个对象,相当于两个人对同一张银行卡进行操作Thread t1=new AccountThread(act);Thread t2=new AccountThread(act);t1.setName("t1");t2.setName("t2");t1.start();t2.start();}}

安全情况下:

t2对001账户取款成功 剩余余额:0.0

t1对001账户取款成功 剩余余额:5000.0

但是会出现线程安全问题:

t2对001账户取款成功 剩余余额:5000.0

t1对001账户取款成功 剩余余额:5000.0

如何使用线程同步机制解决线程安全问题:

我们只需要将账户类中的取款方法改为:

package com.java.javase.ThreadSafe;/**银行账户*/public class Account {private String no;private double balance;public Account() {}public Account(String no, double balance) {this.no = no;this.balance = balance;}public String getNo() {return no;}public void setNo(String no) {this.no = no;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}// 提供一个取款的方法public void withDraw(double money) {// 使用线程同步机制synchronized (this){// 这几行代码必须是排队的,不能并发// 线程同步机制的语法:// synchronized (){线程同步代码块}// ()中的内容相当关键/*** ()中写什么?* 那要看你想要那些线程同步?* 假设你只希望t1,t2,t3线程在该处排队执行,则需要在()中写一个t1 t2 t3共享的对象* 这里的共享对象是:账户对象*/try{Thread.sleep(1000);}catch (InterruptedException e){}double before=this.balance;double after=before-money;this.setBalance(after);}}}

synchronized执行原理:

1.假设t1和t2线程并发,开始执行同步代码块的时候,肯定有一个先有一个后

2.假设t1先执行了,遇到了synchronized关键字,这个时候自动找”后面共享对象“的对象锁,找到之后占有这把锁,然后执行同步代码块中的程序,在程序执行过程中一直都是占有这把锁的,直到同步代码块执行结束,这把锁才会被释放

3.假设t1已经占有这把锁,此时t2也遇到synchronized关键字,也会去占有后面共享对象的这把锁,结果这把锁已经被t1占有,t2只能在同步代码块外面等待t1的结束,直到t1把同步代码块执行结束了,t1归还了这把锁,此时t2终于等到这把锁,然后t2占有这把锁,进入同步代码块执行程序,这样就达到了线程排队执行

synchronized可以出现实例方法上:

package com.java.javase.ThreadSafe;/**银行账户*/public class Account {private String no;private double balance;public Account() {}public Account(String no, double balance) {this.no = no;this.balance = balance;}public String getNo() {return no;}public void setNo(String no) {this.no = no;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}// 提供一个取款的方法/*** 在实例方法上可以使用synchronized吗?可以* synchronized出现在实例方法上,一定锁的是this,这种方式不灵活* 另外还有一个缺点:synchronized出现在实例方法上,表示整个方法体都需要同步* 可能会无故扩大同步的范围,导致程序的执行效率降低,所以这种方式不常用* 优点:代码简洁,如果共享对象一定是this,建议使用这种方式*/public synchronized void withDraw(double money) {double before=this.balance;double after=before-money;try{Thread.sleep(1000);}catch (InterruptedException e){}this.setBalance(after);}}

三、练习题

练习1:

package com.java.javase.Thread;public class ThreadTest {public static void main(String[] args) throws InterruptedException {MyClass mc=new MyClass();Thread t1=new MyThread(mc);Thread t2=new MyThread(mc);t1.setName("t1");t2.setName("t2");t1.start();Thread.sleep(1000); // 确保t1线程先执行t2.start();}}class MyThread extends Thread{private MyClass mc;public MyThread(MyClass mc){this.mc=mc;}public void run(){if(Thread.currentThread().getName().equals("t1")){mc.doSome();}else if(Thread.currentThread().getName().equals("t2")){mc.doOther();}}}class MyClass{public synchronized void doSome(){System.out.println("doSome begin");try{Thread.sleep(1000*10);}catch (InterruptedException e){e.printStackTrace();}System.out.println("doSome over");}/*** doOther方法的执行需要等待doSome方法的结束吗?* 不需要,因为该方法的执行不需要获取锁*/public void doOther(){System.out.println("doOther begin");System.out.println("doOther over");}}

输出结果:

doSome begin

doOther begin

doOther over

doSome over

在上题中的doOther方法上加上synchronized,结果会怎么样?

package com.java.javase.Thread;public class ThreadTest {public static void main(String[] args) throws InterruptedException {MyClass mc=new MyClass();Thread t1=new MyThread(mc);Thread t2=new MyThread(mc);t1.setName("t1");t2.setName("t2");t1.start();Thread.sleep(1000); // 确保t1线程先执行t2.start();}}class MyThread extends Thread{private MyClass mc;public MyThread(MyClass mc){this.mc=mc;}public void run(){if(Thread.currentThread().getName().equals("t1")){mc.doSome();}else if(Thread.currentThread().getName().equals("t2")){mc.doOther();}}}class MyClass{public synchronized void doSome(){System.out.println("doSome begin");try{Thread.sleep(1000*10);}catch (InterruptedException e){e.printStackTrace();}System.out.println("doSome over");}/*** doOther方法的执行需要等待doSome方法的结束吗?* synchronized 出现在实例方法上,表示锁的是this* 需要,因为该方法的执行需要获取锁*/public synchronized void doOther(){System.out.println("doOther begin");System.out.println("doOther over");}}

输出结果:

doSome begin

doSome over

doOther begin

doOther over

synchronized 出现在静态方法上:

package com.java.javase.Thread;public class ThreadTest {public static void main(String[] args) throws InterruptedException {MyClass mc=new MyClass();Thread t1=new MyThread(mc);Thread t2=new MyThread(mc);t1.setName("t1");t2.setName("t2");t1.start();Thread.sleep(1000); // 确保t1线程先执行t2.start();}}class MyThread extends Thread{private MyClass mc;public MyThread(MyClass mc){this.mc=mc;}public void run(){if(Thread.currentThread().getName().equals("t1")){mc.doSome();}else if(Thread.currentThread().getName().equals("t2")){mc.doOther();}}}class MyClass{public synchronized static void doSome(){System.out.println("doSome begin");try{Thread.sleep(1000*10);}catch (InterruptedException e){e.printStackTrace();}System.out.println("doSome over");}/*** doOther方法的执行需要等待doSome方法的结束吗?* synchronized 出现在静态方法上,表示锁的是类锁* 对象可以有多个,但是类锁只有一把,所以需要等待*/public synchronized static void doOther(){System.out.println("doOther begin");System.out.println("doOther over");}}

doSome begin

doSome over

doOther begin

doOther over

四、死锁🔒

package com.java.javase.deadLock;public class ThreadTest {public static void main(String[] args) throws InterruptedException {Object o1=new Object();Object o2=new Object();// t1和t2两个线程共享o1,o2Thread t1=new MyThread1(o1,o2);Thread t2=new MyThread2(o1,o2);t1.start();t2.start();}}class MyThread1 extends Thread{Object o1;Object o2;public MyThread1(Object o1,Object o2){this.o1=o1;this.o2=o2;}@Overridepublic void run() {synchronized (o1){try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o2){}}}}class MyThread2 extends Thread{Object o1;Object o2;public MyThread2(Object o1,Object o2){this.o1=o1;this.o2=o2;}@Overridepublic void run() {synchronized (o2){try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o1){}}}}

五、守护线程和定时器

package com.java.javase.Thread;public class ThreadTest {public static void main(String[] args) throws InterruptedException {Thread t1=new MyThread();t1.setName("备份数据的线程");// 启动线程之前,将线程设置为守护线程t1.setDaemon(true);t1.start();// 主线程:用户线程for(int i=0;i<10;i++){System.out.println(Thread.currentThread().getName()+"---"+i);Thread.sleep(1000);}}}class MyThread extends Thread{@Overridepublic void run() {// 即使是死循环,但由于该线程是守护线程,当用户线程结束,守护线程自动停止int i=0;while (true) {System.out.println(Thread.currentThread().getName() + "---" + (i++));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}

备份数据的线程---7

备份数据的线程---8

main---8

main---9

备份数据的线程---9

备份数据的线程---10

Process finished with exit code 0

定时器:

package com.java.javase.Timer;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class TimerTest01 {public static void main(String[] args) throws Exception{SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date firstTime=sdf.parse("-11-01 14:36:00");// 创建定时器对象Timer timer=new Timer();// 三个参数:指定定时任务,第一次执行时间,间隔多久执行一次timer.schedule(new LogTimerTask(),firstTime,1000*10);}}// 编写一个定时任务类// TimerTask实现了Runnable接口class LogTimerTask extends TimerTask{@Overridepublic void run() {SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");String strTime=sdf.format(new Date());System.out.println(strTime+":完成了一次数据备份");}}

-11-01 14:36:00 016:完成了一次数据备份

-11-01 14:36:10 019:完成了一次数据备份

-11-01 14:36:20 035:完成了一次数据备份

六、实现线程的第三种方式 ,实现Callable接口

package com.java.javase.Thread;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/*** 实现线程的第三种方式:*实现Callable接口*/public class ThreadTest {public static void main(String[] args) throws InterruptedException, ExecutionException {// 创建一个"未来任务类"对象// 需要给一个Callable接口实现类对象FutureTask futureTask=new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {// call()方法就相当于run方法,只不过这个有返回值// 线程执行一个任务,执行之后可能会有一个执行结果System.out.println("call begin");Thread.sleep(1000*10);System.out.println("call over");return new Object();}});// 创建线程对象// 这里是main方法,在主线程中// 在主线程中怎么获取t线程的返回结果?// get()方法的执行会导致当前线程阻塞Thread t=new Thread(futureTask);t.start();futureTask.get();// main方法的这里的程序要想执行必须等待get()方法的结束// 而get()方法可能需要很久System.out.println("拿到执行结果");}}

七、Object类中的wait和notify方法—生产者和消费者模式

package com.java.javase.ProducerAndCustomer;import java.util.ArrayList;import java.util.List;// 使用wait方法和notify方法实现“生产者和消费者模式”public class ThreadTest {public static void main(String[] args) {List list=new ArrayList();Thread t1=new Thread(new Producer(list));Thread t2=new Thread(new Customer(list));t1.setName("生产者线程");t2.setName("消费者线程");t1.start();t2.start();}}// 生产线程class Producer implements Runnable{// 仓库private List list;public Producer(List list) {this.list = list;}@Overridepublic void run() {while(true){// 给仓库对象list加锁synchronized (list){// 大于0,说明仓库中已经有一个元素了if(list.size()>0){try {// 当前线程进入等待状态,并且释放Producer之前占有的list集合的锁list.wait();} catch (InterruptedException e) {e.printStackTrace();}}Object obj = new Object();list.add(obj);System.out.println(Thread.currentThread().getName() + "-----生产了一个" + obj);list.notifyAll();}}}}// 消费线程class Customer implements Runnable{private List list;public Customer(List list) {this.list = list;}@Overridepublic void run() {while(true){synchronized (list){if(list.size()==0){try {list.wait();} catch (InterruptedException e) {e.printStackTrace();}}Object obj=list.remove(0);System.out.println(Thread.currentThread().getName()+"-----消费了一个"+obj);list.notifyAll();}}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。