java 多线程 总结 案例

来源:互联网 发布:学java软件开发好不好 编辑:程序博客网 时间:2024/05/16 10:29

学完东西后,要学会总结,学会记录笔记,这样才会有更大的收获


首先我们了解线程和进程的基本概念

一、概念(程序 进程 线程)

1、程序:指令集 静态概念

2、进程:操作系统 调度程序 动态概念

3:线程:在进程内多条执行路径 真正的多线程是指多个cpu

二、创建

  1.1  继承Thread +run()

启动:创建类对象+对象.start()

package com.org.pc;/** * 模拟龟兔赛跑 * @author lyy * 创建多线程 继承Thread 重写run(线程体) * 使用线程创建子类对象,调用对象.start() */public class Rabbit extends Thread{@Overridepublic void run() {for (int i = 0; i <100; i++) {System.out.println("兔子跑了"+ i + "步");}}public static void main(String[] args) {Thread t1 = new Rabbit();Thread t2 = new Tortoise();t1.start();t2.start();}} class Tortoise extends Thread{@Overridepublic void run() {for (int i = 0; i <100; i++) {System.out.println("乌龟跑了"+ i + "步");}}}

1.2  实现Runable+run()

启动:使用静态代理

1、创建真实角色

2、创建代理角色 Thread+引用

3、代理角色.start()

/** * 使用Runable 创建 线程 * 1、类实现Runable接口 +重写run() 真实角色类 * 2、启动多线程 使用静态代理 * 1)创建真实角色 * 2)创建代理角色+真实角色引用 * 3)调用.start() * @author lyy * */public class Programer implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println("一边敲代码。。。。。");}}public static void main(String[] args) {//1)创建真实角色Programer pro = new Programer();// 2)创建代理角色+真实角色引用Thread proxy = new Thread(pro);//3)调用.start()proxy.start();for (int i = 0; i < 1000; i++) {System.out.println("一边聊QQ。。。。。");}}}

1.3  实现Callable(了解)

通过Callable接口实现多线程

优点:可以获取返回值


package com.org.pc;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * 使用Callable创建线程 * @author lyy * */public class Call {public static void main(String[] args) throws InterruptedException, ExecutionException {//创建线程ExecutorService ser = Executors.newFixedThreadPool(2);Race tor = new Race("千年王八",1000);Race rabbit = new Race("小兔子",500);//获取值Future<Integer> result1 = ser.submit(tor);Future<Integer> result2 = ser.submit(rabbit);Thread.sleep(2000);//休眠2秒tor.setFlag(false);//停止线程体中的循环rabbit.setFlag(false);//停止线程体中的循环int num1 = result1.get();int num2 = result2.get();System.out.println("大乌龟跑了----->"+num1+"步");System.out.println("小兔子跑了----->"+num2+"步");//停止服务ser.shutdown();}}class Race implements Callable<Integer>{private String name;//名称private long time;//延时时间private boolean flag = true;private int step = 0;//步数public Race(){}public Race(String name) {super();this.name = name;}public Race(String name, int time) {super();this.name = name;this.time = time;}@Overridepublic Integer call() throws Exception {while(flag){Thread.sleep(time);//延时step++;}return step;}public String getName() {return name;}public void setName(String name) {this.name = name;}public long getTime() {return time;}public void setTime(long time) {this.time = time;}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}public int getStep() {return step;}public void setStep(int step) {this.step = step;}}



三:线程运行示意图



 新生-->就绪-->运行-->阻塞-->终止


四:线程的终止(重点)

1、自然终止:线程体正常执行完毕

2、外部干涉

         1)线程类中 定义 线程体使用的标识

         2)线程提供使用该标识

3) 对外提供方法改变该标识

4) 外部根据条件调用该方法


package com.org.status;public class StopDemo1 {public static void main(String[] args) {Study stu = new Study(); new Thread(stu).start();  //外部改变该标识 for (int i = 0; i < 100; i++) { if(i==50){//外部干涉 stu.stop(); }System.out.println("main......"+i);}}}class Study implements Runnable{//1)线程类中 定义 线程体使用的标识private boolean flag =true;@Overridepublic void run() {//2)线程提使用该标识while(flag){System.out.println("Study thread .....");}}//3)、对外提供方法改变该标识public void stop(){this.flag = false;}}


五:阻塞

IsAlive() 判断线程是否还活着,既线程是还未终止

getPriority()获得线程的优先级数值

setPriority() 设置线程的优先级数值

setName()给线程一个名字

getName()取得线程的名字

currentThread()取得当前正在运行的线程对象也就是取得自己本身

  阻塞:join yield  sleep(重点)


1、Join:合并线程


package com.org.status;/** * join:合并线程 * @author lyy * */public class JoinDemo01 extends Thread {public static void main(String[] args) throws InterruptedException {JoinDemo01 join  = new JoinDemo01();Thread t = new Thread(join);//新增t.start();//就绪//cpu调度运行for (int i = 0; i < 100; i++) {if(50 == i){t.join();//main阻塞}System.out.println("main......"+i);}}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("join......"+i);}}}



2、Yield:暂停自己的线程

package com.org.status;import javax.sound.midi.Synthesizer;public class YieldDemo01 extends Thread{public static void main(String[] args) {YieldDemo01 yield = new YieldDemo01();Thread t = new Thread(yield);//新生t.start();//就绪//cpu调度运行for (int i = 0; i < 100; i++) {if(i%20 == 0){//暂停本线程mainThread.yield();}System.out.println("main......."+i);}}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("yield......."+i);}}}



3、Sleep():休眠,不释放锁

         1)、时间相关(倒计时)

package com.org.status;import java.text.SimpleDateFormat;import java.util.Date;/** * 倒计时 * 1、倒数10个数,一秒内打印一个 * 2、倒计时 * @author lyy * */public class SleepDemo01 {public static void main(String[] args) throws InterruptedException {Date endTime = new Date(System.currentTimeMillis() + 10*1000);long end = endTime.getTime();while(true){//输出System.out.println(new SimpleDateFormat("mm:ss").format(endTime));//构建下一秒的时间endTime = new Date(endTime.getTime() - 1000);//等待一秒时间Thread.sleep(1000);//如果在十秒以内继续否则退出if(end -10000 > endTime.getTime()){System.out.println("ending");break;}}}public static void test1() throws InterruptedException{int num = 10;while(true){System.out.println(num--);Thread.sleep(1000);//暂停if(num <= 0){break;}}}}


         2)、模拟网络延时

package com.org.status;/** * Sleep模拟 网络延时 线程不安全的 * @author lyy * */public class SLeepDemo02 {public static void main(String[] args) {//真实角色Web12306 web = new Web12306();//代理角色Thread t1 = new Thread(web,"工程师");Thread t2 = new Thread(web,"黄牛已");Thread t3 = new Thread(web,"路人甲");//启动线程t1.start();t2.start();t3.start();}}class Web12306 implements Runnable{private int num = 80;@Overridepublic void run() {while(true){if(num <= 0){break;//跳出循环}try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}}}


同步:并发多个线程访问同一份资源确保资源安全  ==> 线程安全

Synchronized  --> 同步

一、同步块

Synchronized(引用类型|this|类.class){

 }


package com.org.syn;public class SynDemo01 {public static void main(String[] args) {//真实角色Web123 web = new Web123();//代理角色Thread t1 = new Thread(web,"工程师");Thread t2 = new Thread(web,"黄牛已");Thread t3 = new Thread(web,"路人甲");//启动线程t1.start();t2.start();t3.start();}}class Web123 implements Runnable{private int num = 10;private boolean flag = true;@Overridepublic void run() {while(flag){test3();}}//线程不安全 锁定资源不正确public void test6(){//a b cif(num <= 0){flag =false;//跳出循环return;}synchronized (this) {try {Thread.sleep(500);//模拟 延时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}}//线程不安全 锁定资源不正确public void test5(){//a b csynchronized ((Integer)num) {if(num <= 0){flag =false;//跳出循环return;}try {Thread.sleep(500);//模拟 延时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}}//锁定范围不正确public void test4(){//a b csynchronized (this) {if(num <= 0){flag =false;//跳出循环return;}try {Thread.sleep(500);//模拟 延时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}}//线程安全,锁定正确public void test3(){//a b csynchronized (this) {if(num <= 0){flag =false;//跳出循环return;}try {Thread.sleep(500);//模拟 延时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}}public synchronized void test2(){if(num <= 0){flag =false;//跳出循环return;}try {Thread.sleep(500);//模拟 延时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}//线程不安全public void test1(){if(num <= 0){flag =false;//跳出循环return;}try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"抢到了"+num--);}}


二、同步方法

Synchronized

 

线程安全的效率慢,保证资源的正确

线程不安全的效率快

 

三、死锁:过多的同步容易造成死锁



package com.org.syn;/** * 过多的方法可能造成死锁 * @author lyy * */public class SncDemo3 {public static void main(String[] args) {Object g = new Object();Object m = new Object();Test t1 = new Test(g,m);Test t2 = new Test(g,m);Thread proxy1 = new Thread(t1);Thread proxy2 = new Thread(t2);proxy1.start();proxy2.start();}}class Test implements Runnable{Object goods;Object money;public Test(Object goods, Object money) {this.goods = goods;this.money = money;}@Overridepublic void run() {while(true){test();}}public void test(){synchronized (goods) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}synchronized (money) {//System.out.println("一手给货");}}}class test2 implements Runnable{Object goods;Object money;public test2(Object goods, Object money) {this.goods = goods;this.money = money;}@Overridepublic void run() {while(true){test();}}public void test(){synchronized (money) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}synchronized (goods) {System.out.println("一手给货");}}}


解决方法:生产者消费者模式

先生产,在消费

package com.org.pro;/** * 一个场景,一个共同的资源 * 生产者和消费者模式信号灯法 * wait() 等待 释放锁 sleep 不释放锁  * notify()/notifyAll() 唤醒 * 与 synchronized * @author lyy * */public class Movie {private String pic;//信号灯//flag --> T 生产者生产 消费者消费 生产完成后 通知消费//flag --> f 消费者消费 生产者等待 消费完成后唤醒生产private boolean flag = true;public synchronized void play(String pic){if(!flag){//生产者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//开始生产try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("生产了:"+pic);//生产完毕this.pic = pic;//通知消费this.notify();//生产者停下this.flag=false;}public synchronized void watch(){if(flag){//消费者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}try {//开始消费Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("消费了:"+pic);//消费完毕//通知生产this.notify();//消费停止this.flag = true;}}}


package com.org.pro;/** * 生产者 * @author lyy */public class Player implements Runnable{private Movie m;public Player(Movie m) {super();this.m = m;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(0 == i%2){m.play("左青龙");}else{m.play("右白虎");}}}}

package com.org.pro;/** * 消费者 * @author lyy * */public class Watcher implements Runnable{private Movie m;public Watcher(Movie m) {super();this.m = m;}@Overridepublic void run() {for (int i = 0; i < 100; i++) {m.watch();}}}

package com.org.pro;public class App {public static void main(String[] args) {//共同的资源Movie m = new Movie();//多线程Player p = new Player(m);Watcher w = new Watcher(m);new Thread(p).start();new Thread(w).start();}}


新生--> start -->就绪-->运行-->阻塞-->终止

线程是一个好用但是也有点复杂的技术,博主会的也只是一点点皮毛,希望有机会能和各位多多学习!有什么不对的地方,请大家多多包涵!

想要更加熟练的运用线程还需要多多深入了解!


2 0