Java多线程详解及其代码实现

编程入门 行业动态 更新时间:2024-10-21 10:15:09

Java<a href=https://www.elefans.com/category/jswz/34/1767532.html style=多线程详解及其代码实现"/>

Java多线程详解及其代码实现

多线程01:概述

多线程02:线程,进程,多线程


  • Process:进程
  • THread:线程

多线程03:继承Thread类


  • 多条线程是同时运行的(交替执行)
package Base;//创建线程的方式一:继承Thread类,重写run()方法,创建线程对象调用start开启线程
//总结:线程开启不一定立即执行,由CPU调度public class TestThread1 extends Thread {@Overridepublic void run() {//run方法线程体for (int i = 0; i < 200; i++) {System.out.println(i+"我在写代码");}}public static void main(String[] args) {//main线程,主线程//创建一个线程对象TestThread1 testThread1 = new TestThread1();//调用start()方法开启线程,,,不能调用run方法testThread1.start();for (int i = 0; i < 2000; i++) {System.out.println(i+"我在学习多线程");}}
}

多线程03:网图下载

package Base;import org.apachemons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.URL;//练习Thread,实现多线程同步下载图片
public class TestThread1 extends Thread {private  String url; //网络图片地址private  String name;//保存的文件名public TestThread1(String url, String name) {this.url = url;this.name = name;}//下载图片的线程执行体@Overridepublic void run() {//使用下载器webDownLoader webDownLoader = new webDownLoader();webDownLoader.downloader(url,name);System.out.println("下载了文件名为:"+name);}//主线程public static void main(String[] args) {//使用构造方法传入图片地址和保存图片的名称TestThread1 t1 = new TestThread1(".png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MzMzMTk0Mg==,size_16,color_FFFFFF,t_70","2.jpg");//多个线程是同时执行的t1.start();}
}//首先写一个下载器
class webDownLoader{//下载方法public void downloader(String url, String name){try {FileUtils.copyURLToFile(new URL(url),new File(name));} catch (IOException e) {e.printStackTrace();System.out.println("IO异常,downLoader方法出现问题");}}
}

实现Runnable的接口

package Base;public class Demo2 implements Runnable{@Overridepublic void run() {for (int i = 0; i < 200; i++) {System.out.println(i+"我在学习java");}}public static void main(String[] args) {Demo2 demo2 = new Demo2();new Thread(demo2).start();for (int i = 0; i < 1000; i++) {System.out.println("java真香");}}}
  • 对比小结

多线程06:初识并发问题

package Base;//多个线程同时操作同一个对象
//买火车票的例子public class Demo2 implements Runnable{private int ticket = 10;@Overridepublic void run() {while(true){if (ticket<=0){break;}ticket--;//通过Thread.currentThread().getName()方法获得当前线程的名字System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket+"票");}}public static void main(String[] args) {Demo2 demo2 = new Demo2();new Thread(demo2,"王姐").start();new Thread(demo2,"li姐").start();new Thread(demo2,"zhang姐").start();}
}
  • 发现问题:多个线程操作一个资源时。线程不安全,数据紊乱

多线程07:乌兔赛跑

package Base;public class Demo2 implements Runnable{//胜利者private static String winner;@Overridepublic void run() {for (int i = 0; i <= 100; i++) {//模拟兔子睡觉if (Thread.currentThread().getName().equals("兔子")&&i%10==0){try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}//判断比赛是否结束boolean flag = gameOver(i);//如果比赛结束就停止比赛if (flag){break;}System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");}}//判断比赛是否完成public boolean gameOver(int steps){if (winner!=null){   //已经存在胜利者了return true;}if (steps>=100){winner=Thread.currentThread().getName();System.out.println("winner is "+winner);return true;}return false;}public static void main(String[] args) {//创建一个赛道Demo2 demo2 = new Demo2();new Thread(demo2,"乌龟").start();new Thread(demo2,"兔子").start();}
}

多线程08:实现Callable接口(了解即可)

  • 改进下载网图
package Base;import org.apachemons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.URL;
import java.util.concurrent.*;//练习Thread,实现多线程同步下载图片
class Demo3 implements Callable<Boolean> {private  String url; //网络图片地址private  String name;//保存的文件名public Demo3(String url, String name) {this.url = url;this.name = name;}//下载图片的线程执行体@Overridepublic Boolean call() {//使用下载器webDownLoader webDownLoader = new webDownLoader();webDownLoader.downloader(url,name);System.out.println("下载了文件名为:"+name);return true;}//主线程public static void main(String[] args) throws ExecutionException, InterruptedException {//使用构造方法传入图片地址和保存图片的名称Demo3 t1 = new Demo3(".png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MzMzMTk0Mg==,size_16,color_FFFFFF,t_70","2.jpg");//多个线程是同时执行的ExecutorService ser = Executors.newFixedThreadPool(3);Future<Boolean> r1 = ser.submit(t1);boolean r = r1.get();System.out.println(r);ser.shutdownNow();}}//首先写一个下载器
class webDownLoader1{//下载方法public void downloader(String url, String name){try {FileUtils.copyURLToFile(new URL(url),new File(name));} catch (IOException e) {e.printStackTrace();System.out.println("IO异常,downLoader方法出现问题");}}
}

多线程09:静态代理模式

package Base;/*** 静态代理模式总结* 真实对象和代理对象都要实现一个共同的接口* 代理对象要代理真实角色* 好处:*     代理对象可以做很多真实对象做不了的事情*     真实对象专注做自己的事情*/public class Demo3  {public static void main(String[] args) {WeddingCCompany weddingCCompany = new WeddingCCompany(new You());weddingCCompany.happyMarry();}
}//共同的接口
interface marry{void happyMarry();
}//真是角色  你去结婚
class You implements marry{@Overridepublic void happyMarry() {System.out.println("woyaojiehunle gaoshuwoaini ");}
}//代理角色  帮助你结婚
class WeddingCCompany implements marry{private marry target;public WeddingCCompany(marry target) {this.target = target;}@Overridepublic void happyMarry() {after();this.target.happyMarry();before();}private void after() {System.out.println("xingfu");}private void before() {System.out.println("tongku");}
}

多线程10:Lamada表达式



package Base;public class Demo3 {public static void main(String[] args) {// lambda表达式test p = (int a) ->{System.out.println("I Love---"+a); };//简化1.去掉参数类型test p = (a) ->{System.out.println("I Love---"+a); };p.love(520);  //  I Love---520//简化2.去掉参数类型和()test p = a ->{System.out.println("I Love---"+a); };p.love(521);  //I Love---521//简化3.去掉参数类型和()和{}//注意:lambda表达式只能有一行代码的情况下才能成为一行,如果有多行,则使用代码块({})包裹;//     多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号//前提:接口必须是函数式接口(一个接口中只有一个方法)test p = a ->System.out.println("I Love---"+a);p.love(521);  //I Love---521}}interface test{void love(int a);
}

多线程11:线程停止



package Base;//测试stop
//1.建议线程正常停止--->    利用次数  ,不建议死循环
//2.建议使用标志位--->这只一个标志位
//3.不要使用stop或者destroy等过的或者JDK不建议的使用方法public class Demo3 implements Runnable {//设置一个标志位private boolean flag=true;@Overridepublic void run() {int i=0;while (flag){//在内部进行i++也可以System.out.println("run -------Thread"+i++);}}//设置一个公开的方法停止线程,转换标志位public void stop(){this.flag=false;}public static void main(String[] args) {Demo3 demo3 = new Demo3();new Thread(demo3).start();for (int i = 0; i < 1000; i++) {System.out.println("main     "+i);if (i==900){//调用stop方法,切换标志位,停止线程demo3.stop();System.out.println("该线程停止");}}}
}

多线程12:线程休眠—sleep

  • 模拟网络延时
package Base;//多个线程同时操作同一个对象
//买火车票的例子public class Demo3 implements Runnable{private int ticket = 10;@Overridepublic void run() {while(true){if (ticket<=0){break;}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}ticket--;//通过Thread.currentThread().getName()方法获得当前线程的名字System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket+"票");}}public static void main(String[] args) {Demo3 demo2 = new Demo3();new Thread(demo2,"王姐").start();new Thread(demo2,"li姐").start();new Thread(demo2,"zhang姐").start();}
}
  • 模拟倒计时
//模拟倒计时public static void ten() throws InterruptedException {int t = 10;while(true){Thread.sleep(1000);System.out.println(t);t--;if (t<0){break;}}}
}
  • 打印系统当前时间
 public static void main(String[] args)  {//打印当前系统时间Date date = new Date(System.currentTimeMillis());  //获取当前系统的时间while(true){try {Thread.sleep(1000);System.out.println(new SimpleDateFormat("HH:MM:ss").format(date));date = new Date(System.currentTimeMillis());  //更新当前时间} catch (InterruptedException e) {e.printStackTrace();}}}

多线程13:线程礼让——yield

public class Demo3 {public static void main(String[] args) {MyYield m1 = new MyYield();new Thread(m1,"a").start();new Thread(m1,"b").start();}}class MyYield implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"线程开始执行");Thread.yield();  //线程礼让System.out.println(Thread.currentThread().getName()+"线程执行完毕");}
}a线程开始执行
b线程开始执行
a线程执行完毕
b线程执行完毕
  • 礼让不一定成功,看CPU心情

多线程14:线程强制礼让——join

  • 注意调用方法
package Base;public class Demo3 implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println("线程Vip来了   "+i);}}public static void main(String[] args) throws InterruptedException {Demo3 demo3 = new Demo3();Thread thread = new Thread(demo3, "aa");thread.start();for (int i = 0; i < 500; i++) {if (i==200){thread.join();}System.out.println("main  "+i);}}
}

多线程15:观测线程状态

package Base;public class Demo3 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("///");});//观察转台Thread.State state = thread.getState();System.out.println(state);//观察启动状态thread.start();state = thread.getState();  //不用每次都创建一个新的对象System.out.println(state);while(state!=Thread.State.TERMINATED){//只要线程不终止,就会一直输出Thread.sleep(1000);state =thread.getState();System.out.println(state);}}
}NEW
RUNNABLE
RUNNABLE
RUNNABLE
TIMED_WAITING
RUNNABLE
TIMED_WAITING
TIMED_WAITING
RUNNABLE
TIMED_WAITING
TIMED_WAITING
RUNNABLE
///
TERMINATED

注意:lambda表达式的使用处
注意:线程结束后就不能再start()调用了

多线程15:线程的优先级(priority)

  • 注意:优先级高的不一定先跑,但是大多数情况是这样
  • 注意:优先级的设定建议在start()前调度
package Base;public class Demo3 {public static void main(String[] args) {//主线程默认优先级//使用Thread.currentThread().getPriority()来获取本身的优先级System.out.println(Thread.currentThread().getName() + "--->" + Thread.currentThread().getPriority());bbb bbb = new bbb();Thread t1 = new Thread(bbb, "lhao");//先设置优先级在启动Thread t2 = new Thread(bbb, "lihao");t2.setPriority(Thread.MAX_PRIORITY);t2.start();Thread t5 = new Thread(bbb, "lao");t5.setPriority(4);t5.start();Thread t4 = new Thread(bbb, "lao");t4.setPriority(6);t4.start();}
}class bbb implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"---->"+Thread.currentThread().getPriority());}
}

多线程17:守护线程(daemon)

  • 虚拟机不用管守护线程执没执行完,只管用户线程执行完毕就行
  • 虚拟机停止也需要一段时间
  • 使用 thread.setDaemon(true); 来设置守护线程
package Base;public class Demo3 {public static void main(String[] args) {God god = new God();You you = new You();Thread thread = new Thread(god);//使用  thread.setDaemon来设置守护线程thread.setDaemon(true);  //默认是false表示用户线程,  正常的线程都是用户线程thread.start(); // 守护线程启动new Thread(you).start();//用户线程启动}
}class You implements Runnable{@Overridepublic void run() {for (int i = 0; i < 36500; i++) {System.out.println("我的一生很快乐");}System.out.println("goodbye-----world");}
}class God implements Runnable{@Overridepublic void run() {while(true){System.out.println("上帝保护着我");}}
}

多线程18:线程同步机制

多线程19:三大不安全的案例

注意:使用Thread.sleep来放大问题的发生性

  • 不安全的买票----有负数
package Base;public class Demo3 {public static void main(String[] args) {BuyTicket st = new BuyTicket();Thread t1 = new Thread(st,"张三");Thread t2 = new Thread(st,"李四");Thread t3 = new Thread(st,"王五");t1.start();t2.start();t3.start();}
}class BuyTicket implements Runnable{//票private int ticket = 10;//设置外部停止标志boolean flag = true;@Overridepublic void run() {//买票while (flag){test();}}//买票的方法public void test()  {//判断是否有票if (ticket>10||ticket<=0){System.out.println("对不起,票已经售空");flag =false;}//模拟延时try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"买到了"+ticket--);}
}
  • 不安全的取钱
package Base;public class Demo3 {public static void main(String[] args) {//账户Account account = new Account(1000000,"结婚基金");Drawing you = new Drawing(account,500000,"你");Drawing girlFriend = new Drawing(account,1000000,"GirlGood");you.start();girlFriend.start();}
}//账户
class Account{int money; //余额String name;//卡名public Account(int money, String name) {this.money = money;this.name = name;}
}//银行:模拟取款
class Drawing extends Thread{Account account;//账户//取了多少钱int drawingMoney;//手里有多少钱int nowMoney;public Drawing(Account account, int drawingMoney, String name) {//调用父类的构造方法super(name);this.account = account;this.drawingMoney = drawingMoney;}//取钱@Overridepublic void run() {//判断有没有钱if (account.money-drawingMoney<0){System.out.println(Thread.currentThread().getName()+"钱不够,去不了");return;}//模拟延时   sleep可以放大问题的发生行try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//卡上的钱account.money = account.money-drawingMoney;//你手里的钱nowMoney = drawingMoney +nowMoney;System.out.println(account.name+"余额为:"+account.money);//此时Thread.currentThread().getName() =  this.getName()System.out.println(Thread.currentThread().getName()+"手里的钱"+nowMoney);}
}结婚基金余额为:-500000
结婚基金余额为:-500000
你手里的钱500000
GirlGood手里的钱1000000
  • 线程不安全的集合
package Base;import java.util.ArrayList;
import java.util.List;public class aaa {public static void main(String[] args) {List<String> list =new ArrayList<>();for (int i = 0; i < 10000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}
结果为:9998
因为:两个线程同一瞬间操作了同一位置,添加到了同一个位置,覆盖掉了,元素就少了

多线程20:同步方法及同步块

  • synchronized相当于一个修饰符 ,修饰方法变为===>同步方法

  • 加上synchronize就相当于排队 上锁 不能抢

  • synchronize方法锁的是类本身

  • synchronize同步块的锁的是任何对象,锁的对象为变化的对象(增删改),块中为你想要执行的语句

//买票的方法public  synchronized void test()  {//判断是否有票if (ticket>10||ticket<=0){System.out.println("对不起,票已经售空");flag =false;return;}//模拟延时try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"买到了"+ticket--);}
}在买票的方法上加了synchronize,变为同步方法(上锁了),
锁的是方法所在的类的对象(本身)
上面取钱的例子:如果锁的是取钱的方法实际上锁的是该方法所在的类对象--银行,
但是银行没有变化(增删改),所以我们要锁变化的对象(账户),
所以使用同步块然后传入账户的类对象;
//取钱@Overridepublic  void run() {synchronized (account){if (account.money-drawingMoney<0){System.out.println(Thread.currentThread().getName()+"钱不够,去不了");return;}//模拟延时   sleep可以放大问题的发生行try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//卡上的钱account.money = account.money-drawingMoney;//你手里的钱nowMoney = drawingMoney +nowMoney;System.out.println(account.name+"余额为:"+account.money);//此时Thread.currentThread().getName() =  this.getName()System.out.println(Thread.currentThread().getName()+"手里的钱"+nowMoney);}
结婚基金余额为:500000
你手里的钱500000
GirlGood钱不够,去不了
package Base;import java.util.ArrayList;
import java.util.List;public class aaa {public static void main(String[] args) {List<String> list = new ArrayList<>();for (int i = 0; i < 100; i++) {new Thread(() -> {synchronized (list) {list.add(Thread.currentThread().getName());}}).start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(list.size());}
}
结果为:100

多线程21:CopyOnWriteArrayList

  • JUC下的一个线程安全的集合(copyonwritearraylist)
package Base;import java.util.concurrent.CopyOnWriteArrayList;public class aaa {public static void main(String[] args) {CopyOnWriteArrayList<String> c = new CopyOnWriteArrayList();for (int i = 0; i < 1000; i++) {new Thread(()->{c.add(Thread.currentThread().getName());}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(c.size());}
}
不用同步快也可以输出1000,
因为CopyOnWriteArrayList是他人写好的线程安全的集合

多线程22:死锁 (多个线程互相抱着对方资源,然后形成僵持)

package Base;//死锁:多个线程互相抱着对方资源,然后形成僵持
public class aaa {public static void main(String[] args) {makeUp g1 = new makeUp(0,"灰姑娘");makeUp g2 = new makeUp(1,"白雪公主");g1.start();g2.start();}
}//口红
class Lipstick{}//镜子
class Mirror {}//化妆
class makeUp extends Thread{//需要的资源只有一份,用static来修饰保证只有一份,用static修饰的只有一份static Lipstick l = new Lipstick();static Mirror m = new Mirror();int choice;//选择String girlName;//使用化妆品的人//构造方法好赋值public makeUp( int choice, String girlName) {this.choice = choice;this.girlName = girlName;}//线程中调用化妆的方法@Overridepublic void run() {try {makeup();} catch (InterruptedException e) {e.printStackTrace();}}//化妆的方法private void makeup() throws InterruptedException {if (choice==0){synchronized (l){System.out.println(this.girlName+"拿到了口红的锁");Thread.sleep(1000);synchronized (m){System.out.println(this.girlName+"获得镜子的锁");}}}else{synchronized (m){System.out.println(this.girlName+"拿到了镜子的锁");Thread.sleep(2000);synchronized (l){System.out.println(this.girlName+"获得口红的锁");}}}}
}被卡死了:
灰姑娘拿到了口红的锁
白雪公主拿到了镜子的锁
  • 所以需要将同步块中的两个对象锁变为一个就不会出现死锁的问题了、
  • 用static修饰的变量(资源)只有一份

Lock锁–接口

package Base;import java.util.concurrent.locks.ReentrantLock;public class bbb {public static void main(String[] args) {TestLock t1 = new TestLock();TestLock t2 = new TestLock();TestLock t3 = new TestLock();t1.start();t2.start();t3.start();}
}class TestLock extends Thread{private int ticket =10;//定义锁ReentrantLock lock =new ReentrantLock();@Overridepublic void run() {while(true){try{//显示加锁lock.lock();if(ticket>0){System.out.println(ticket--);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}else{System.out.println("票没了");break;}}finally {//解锁lock.unlock();}}}
}
  • 使用的是Lock的实现类ReentrantLock
  • 需要使用try–finally
  • Lock是一个接口

多线程24:生产者消费者问题



设置标志位

多线程24:信号灯法

package Base;//测试:信号灯法,标志位
//生产者,消费者,产品,缓冲区public class bbb {public static void main(String[] args) {Tv tv = new Tv();new Player(tv).start();new Watcher(tv).start();}}class Player extends Thread{Tv tv;public Player(Tv tv) {this.tv = tv;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {if (i%2==0){this.tv.play("kuaile da");} else {this.tv.play("douyin ");}}}
}class Watcher extends Thread{Tv tv;public Watcher(Tv tv) {this.tv = tv;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {tv.watch();} catch (InterruptedException e) {e.printStackTrace();}}}
}class Tv{String voice;boolean flag = true;public synchronized void play(String voice){if (!flag){try {//让其等待this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("演员表演了"+voice);//通知唤醒this.notifyAll();this.voice= voice;this.flag =!this.flag;}public synchronized void watch() throws InterruptedException {if (flag){this.wait();}System.out.println("观看了"+voice);this.notifyAll();this.flag =!this.flag;}}

线程池

package Base;//测试:信号灯法,标志位import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class bbb {public static void main(String[] args) {//1.创建服务,创建线程池  规定线程池的数量ExecutorService service = Executors.newFixedThreadPool(10);//2,执行service.execute(new MyThread());service.execute(new MyThread());service.execute(new MyThread());service.execute(new MyThread());//3.关闭链接service.shutdown();}}class MyThread implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}结果:
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-4

更多推荐

Java多线程详解及其代码实现

本文发布于:2024-02-13 11:50:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1758689.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多线程   详解   代码   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!