多线程

  • 是程序中执行的线程。Java虚拟机允许应用程序同时执行多个执行线程。

    每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守护程序。 当在某个线程中运行的代码创建一个新的Thread对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护线程。

    当Java虚拟机启动时,通常有一个非守护进程线程(通常调用某些指定类的名为main的方法)。 Java虚拟机将继续执行线程,直到发生以下任一情况:

    • 已经调用了Runtime类的exit方法,并且安全管理器已经允许进行退出操作。
    • 所有不是守护进程线程的线程都已经死亡,无论是从调用返回到run方法还是抛出超出run方法的run

    创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:


    class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeThread p = new PrimeThread(143); p.start();

    另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:


    class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeRun p = new PrimeRun(143); new Thread(p).start();

    每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

    除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException

    要点

    1.线程就是独立的执行路径;

    2.在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;main()称之为主线程,为系统的入口,用于执行整个程序;

    3.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的。

    4.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;线程会带来额外的开销,如cpu调度时间,并发控制开销。

    5.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致.

    继承Thread类

    实现编码

    ``

    package wang.com.demo01;import org.apache.commons.io.FileUtils;import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    //联系Thread,实现多线程下载图片
    public class TestThread02 extends Thread{private String url;//地址图片的网络private String name;//图片的名字//通过构造器传参数public TestThread02(String url,String name) {this.url = url;this.name = name;}
    //下载图片的执行体@Overridepublic void run() {WebDownlonder webDownlonder = new WebDownlonder();webDownlonder.downlonder(url,name);System.out.println("下载了文件,文件名为"+name);}public static void main(String[] args) {TestThread02 t1 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/01.jpg","1.jpg");TestThread02 t2 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/02.jpg","2.jpg");TestThread02 t3 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/03.jpg","3.jpg");t1.start();t2.start();t3.start();}
    }
    //下载器
    class WebDownlonder{//下载方法public void downlonder(String url,String name){try {FileUtils.copyURLToFile(new URL(url),new File(name));} catch (IOException e) {System.out.println("捕获错误,下载错误");}}
    }
    

Runnable接口

  • 另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:


    class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeRun p = new PrimeRun(143); new Thread(p).start();

    每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

    实现代码

package wang.com.demo01;import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.URL;public class TestRunnable02 implements Runnable{private String url;//图片的网络地址private String name;//图片的名字//通过构造器传参数public TestRunnable02(String url,String name) {this.url = url;this.name = name;}//下载图片的执行体@Overridepublic void run() {WebDownlonder webDownlonder = new WebDownlonder();webDownlonder.downlonder(url,name);System.out.println("下载了文件,文件名为"+name);}public static void main(String[] args) {TestThread02 t1 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/01.jpg","1.jpg");TestThread02 t2 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/02.jpg","2.jpg");TestThread02 t3 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/03.jpg","3.jpg");new Thread(t1).start();new Thread(t2).start();new Thread(t3).start();}
}

并发初识

``

package wang.com.demo01;
//多线程实现同一个对象
//抢票例子
//发现问题:多个线程操作同一个资源的情况下,资源不安全,数据紊乱.
public class TestThread implements Runnable{private int num = 10;@Overridepublic void run() {while (true){if(num<=0)break;try {Thread.sleep(200);} catch (InterruptedException e) {System.out.println("睡眠失败");}System.out.println(Thread.currentThread().getName()+"抢到了第"+num--+"票");}}public static void main(String[] args) {TestThread testThread = new TestThread();new Thread(testThread,"王浩").start();new Thread(testThread,"汪磊").start();new Thread(testThread,"阿彬").start();}
}

龟兔赛跑

``

package wang.com.demo01;
//龟兔赛跑
public class Race 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(10);} catch (InterruptedException e) {System.out.println("捕获睡眠失败");}}//判断比赛是否结束Boolean flag = gameOver(i);if (flag) {break;}System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");}}private boolean gameOver(int steps) {//判断有没有获胜者if (winner != null) {return true;} else {if (steps >= 100) {winner = Thread.currentThread().getName();System.out.println("获胜者是" + winner);return true;}}return false;}//一个进程实现多个对像的处理public static void main(String[] args) {Race race = new Race();new Thread(race, "兔子").start();new Thread(race, "乌龟").start();}
}

实现Callable接口(了解)

``

package wang.com.demo02;import org.apache.commons.io.FileUtils;
import wang.com.demo01.TestThread02;
import wang.com.demo02.WebDownlonder;import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;public class TestCallable implements Callable<Boolean>{private String url;//图片的网络地址private String name;//图片的名字//通过构造器传参数public TestCallable(String url,String name) {this.url = url;this.name = name;}//下载图片的执行体@Overridepublic Boolean call() {WebDownlonder webDownlonder = new WebDownlonder();webDownlonder.downlonder(url,name);System.out.println("下载了文件,文件名为"+name);return true;}public static void main(String[] args) throws ExecutionException,InterruptedException {TestCallable t1 = new TestCallable("http://www.kuangstudy.com/assert/course/c1/01.jpg","1.jpg");TestCallable t2 = new TestCallable("http://www.kuangstudy.com/assert/course/c1/02.jpg","2.jpg");TestCallable t3 = new TestCallable("http://www.kuangstudy.com/assert/course/c1/03.jpg","3.jpg");//创建执行服务ExecutorService ser = Executors.newFixedThreadPool(3);//提交执行Future<Boolean> r1 = ser.submit(t1);Future<Boolean> r2 = ser.submit(t2);Future<Boolean> r3 = ser.submit(t3);//获取结果boolean rs1 = r1.get();boolean rs2 = r2.get();boolean rs3 = r3.get();System.out.println(rs1);System.out.println(rs2);System.out.println(rs3);//关闭服务ser.shutdownNow();}
}
class WebDownlonder{//下载方法public void downlonder(String url,String name){try {FileUtils.copyURLToFile(new URL(url),new File(name));} catch (IOException e) {System.out.println("捕获错误,下载错误");}}}

静态代理模式

静态代理模式总结:

1.真实对象与代理对象都实现同一个接口
2.代理对象代理真实对象

好处:

1.静态的代理对象可以实现更多的方法
2.真实的对象可以专注与自己的事情

``

package wang.com.demo03;
//静态代理模式总结:
//1.真实对象与代理对象都实现同一个接口
//2.代理对象代理真实对象//好处:
//静态的代理对象可以实现更多的方法
//真实的对象可以专注与自己的事情
public class StacticProxy {public static void main(String[] args) {//静态代理模式与Thread实现Runnable接口是一样的new Thread(new Runnable() {@Overridepublic void run() {System.out.println("年轻人,耗子尾汁");}}).start();//可以说多线程就是一种静态代理模式new WeddingCompany(new You()).HappyMarry();}
}
//提供一个Marry接口
interface Marry{void HappyMarry();
}
//真实对象实现接口
class You implements Marry{@Overridepublic void HappyMarry() {System.out.println("今天王林彬结婚了");}
}
//代理对象实现接口
class WeddingCompany implements Marry{private Marry target;//代理对象代理谁?--->通过真实对象传递来的真实对象public WeddingCompany(Marry target) {this.target = target;}@Overridepublic void HappyMarry() {before();this.target.HappyMarry();//通过构造函数传进来的真实对像after();}private void after() {System.out.println("发现孩子不是自己的");}private void before() {System.out.println("王林彬未婚先孕");}}

Lambda表达式(个人感觉作用不大,代码可读性差)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OaDZJpgU-1605706824728)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\T00_B_]K[ET@1BCD`0JTCYX.png)]

局部内部类:main中的类

静态内部类:class中的static的类

匿名内部类:没有名字的类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DamrfWtD-1605706824731)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201116200155223.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ypgT2h25-1605706824732)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201116200241577.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WXrfp9SG-1605706824734)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201116200317262.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ckebyLnX-1605706824735)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\R726696VX[IH`L0J63M[B6K.png)]

线程停止(通过自己设置的标识符来决定线程是否要停止)

``

package wang.com.demo03;
public class TestStop implements Runnable {//1.设置一个标识位private Boolean flag = true;@Overridepublic void run() {int i=0;while(flag) {System.out.println("run>>>..."+i++);}}//2.改变标识位void Stop(){this.flag = false;System.out.println("线程结束");}public static void main(String[] args) {TestStop testStop = new TestStop();new Thread(testStop).start();for (int i = 0; i < 100; i++) {System.out.println("main..."+i);//3.调用stop标志位让线程停止if(i == 66){testStop.Stop();System.out.println("结束了");}}}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XAxkNz6f-1605706824736)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143521922.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m22y3rF6-1605706824737)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143602956.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urIAyOSx-1605706824738)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143651888.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1upUQzP-1605706824738)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C{GDN_R`SP]U769BKJU${354.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4P7MV7TR-1605706824739)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143743020.png)]

线程休眠( Thread.Sleep() )

线程休眠
sleep(时间)指定当前线程阻塞的毫秒数;
sleep存在异常InterruptedException;
sleep时间达到后线程进入就绪状态;
sleep可以模拟网络延时,倒计时等。
每一个对象都有一个锁,sleep不会释放锁;


``[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MiWVnVj-1605706824740)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\L00L5Y7F3{4B$U9VY[GS)]2R.png)

package wang.com.demo03;import java.text.SimpleDateFormat;
import java.util.Date;//模拟倒计时
public class TestSleep02{public static void main(String[] args) {Date startTime = new Date(System.currentTimeMillis());//获取系统的当前时间while (true){try {Thread.sleep(1000);System.out.println(new SimpleDateFormat("HH,mm,ss").format(startTime));startTime = new Date(System.currentTimeMillis());//获取系统的当前时间} catch (InterruptedException e) {e.printStackTrace();}}}//打印当前系统时间/*private static void tenDown() throws InterruptedException {//模拟倒计时int num = 10;for (int i = 10; i > 0; i--) {Thread.sleep(1000);System.out.println(i);}*/}

线程礼让( Thread.yield() )

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\G42Y2_EBPZAJHW_P7PFCV.png)

``

package wang.com.demo03;public class TestYield {public static void main(String[] args) {MyYield myYield = new MyYield();new Thread(myYield,"a").start();new Thread(myYield,"b").start();}}
class MyYield implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"线程开始");Thread.yield();System.out.println(Thread.currentThread().getName()+"线程结束");}
}

线程插队( Thread.join() )

package wang.com.demo03;public class TestJoin implements Runnable{@Overridepublic void run() {for (int i = 0; i < 300; i++) {System.out.println("VIP来了"+i);}}public static void main(String[] args) throws InterruptedException {//将testJoin给Thread代理TestJoin testJoin = new TestJoin();Thread thread = new Thread(testJoin);thread.start();for (int i = 0; i < 500; i++) {if(i==200) {thread.join();//插队}System.out.println("main"+i);}}
}

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\S6424]P@HTSM_YB`Q2Q}N.png)

观察线程状态( thread.start(); )

  • public static enum Thread.State
    extends Enum<Thread.State>
    

    线程状态。线程可以处于以下状态之一:

    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。

    一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。

    • 从以下版本开始:

      • Enum Constant and Description
        BLOCKED 一个线程的线程状态阻塞等待监视器锁定。
        NEW 线程尚未启动的线程状态。
        RUNNABLE 可运行线程的线程状态。
        TERMINATED 终止线程的线程状态。
        TIMED_WAITING 具有指定等待时间的等待线程的线程状态。
        WAITING 等待线程的线程状态

      ``

      package wang.com.demo03;public class TestState {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("/");}});Thread.State state = thread.getState();System.out.println(state);//newthread.start();//runnablestate = thread.getState();System.out.println(state);while (state != Thread.State.TERMINATED) {Thread.sleep(1000);state = thread.getState();System.out.println(state);}}
      }
      

线程的优先级(priority)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zChiPrw-1605706824740)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118165400293.png)]

``

package wang.com.demo03;
//测试线程都优先级
public class TestPriority{public static void main(String[] args) {//主程序为默认优先级System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());MyPriority myPriority = new MyPriority();Thread t1 = new Thread(myPriority);Thread t2 = new Thread(myPriority);Thread t3 = new Thread(myPriority);Thread t4 = new Thread(myPriority);Thread t5 = new Thread(myPriority);Thread t6 = new Thread(myPriority);Thread t7 = new Thread(myPriority);//设置优先级//由程序自己决定t1.start();//自己设置优先级t2.setPriority(1);t2.start();t3.setPriority(3);t3.start();t4.setPriority(6);t4.start();t5.setPriority(2);t5.start();t6.setPriority(8);t6.start();t7.setPriority(4);t7.start();}}
class MyPriority implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());}
}

守护线程(daemon)

``

package wang.com.demo03;public class TestDaemon {public static void main(String[] args) {God god = new God();Yyou you = new Yyou();Thread thread = new Thread(god);thread.setDaemon(true);//默认false为用户线程,正常的线程多为用户线程thread.start();//上帝线程启动new Thread(you).start();}
}
class God implements Runnable{@Overridepublic void run() {while(true){System.out.println("上帝会永远守护你的");}}
}
class Yyou implements Runnable{@Overridepublic void run() {for (int i = 0; i < 36500; i++) {System.out.println("你一生都是开心的活着的");}System.out.println("Bye  world");}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ealZc3b8-1605706824741)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118182104019.png)]

线程同步(三大不安全案例)

案例一

``

package wang.com.syn;public class UnsafeBuyTicket {public static void main(String[] args) {BuyTicket station = new BuyTicket();//多个对像来抢票new Thread(station,"王浩").start();new Thread(station,"阿彬").start();new Thread(station,"汪磊").start();}}
//买票的类
class BuyTicket implements Runnable{//设置票数private int TicketNums = 10;//设置外部标志private  Boolean flag = true;@Overridepublic void run() {while(flag){buy();}}//买票的方法private void buy(){if(TicketNums < 0){flag = false;return;}try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"拿到了第"+TicketNums-- +"张票");}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZ59ZhsJ-1606532453217)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\WRTO[Y[}0SH`@1H_1F6S182.png)]

案例二

``

package wang.com.syn;public class UnsafeBank {public static void main(String[] args) {Account account = new Account(100,"结婚基金");Drawing you = new Drawing(account,50,"你");Drawing GrilFriend = new Drawing(account,100,"GrilFriend");you.start();GrilFriend.start();}
}
class Account {int money;String name;public Account(int money, String name) {this.money = money;this.name = name;}
}
class Drawing extends Thread {int DrawingMoney;Account account;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()+"钱不够,sorry");return;}//sleep可以放大问题的发生性try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}account.money = account.money - DrawingMoney;NowMoney = NowMoney + DrawingMoney;System.out.println(Thread.currentThread().getName()+"账户余额为"+account.money);System.out.println(Thread.currentThread().getName()+"手上的现金为"+NowMoney);}
}

案例三

``

package wang.com.syn;import java.awt.*;
import java.util.ArrayList;
import java.util.List;public class UnsafeList {public static void main(String[] args) {List<String> list = new ArrayList<String>();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());}
}

同步方法及同步块(synchronized) 注:synchronized 同步方法,锁的是this

public synchronized void method(int args){}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mfKphSie-1606532453221)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C()]GJZZVCM@[97PY]KaTeX parse error: Expected 'EOF', got '}' at position 3: NE}̲~4.png)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jh7UTCnH-1606532453222)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122144622626.png)]

synchronized(Obj){ }

案例1

``

package wang.com.syn;
//线程安全出现了负数public class UnsafeBuyTicket {public static void main(String[] args) {BuyTicket station = new BuyTicket();//多个对像来抢票new Thread(station,"王浩").start();new Thread(station,"阿彬").start();new Thread(station,"汪磊").start();}}
//买票的类
class BuyTicket implements Runnable{//设置票数private int TicketNums = 10;//设置外部标志private  Boolean flag = true;@Overridepublic void run() {while(flag){buy();}}//买票的方法//synchronized  同步方法,锁的是thisprivate synchronized void buy(){if(TicketNums < 1){flag = false;return;}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"拿到了第"+TicketNums-- +"张票");}
}

案例2

``

package wang.com.syn;public class UnsafeBank {public static void main(String[] args) {Account account = new Account(100,"结婚基金");Drawing you = new Drawing(account,50,"你");Drawing GrilFriend = new Drawing(account,100,"GrilFriend");you.start();GrilFriend.start();}
}
class Account {int money;String name;public Account(int money, String name) {this.money = money;this.name = name;}
}
class Drawing extends Thread {int DrawingMoney;Account account;int NowMoney;public Drawing(Account account, int DrawingMoney, String name){super(name);this.account = account;this.DrawingMoney = DrawingMoney;}@Overridepublic void run() {synchronized(account){if(account.money - DrawingMoney < 0){System.out.println(Thread.currentThread().getName()+"钱不够,sorry");return;}//sleep可以放大问题的发生性try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}account.money = account.money - DrawingMoney;NowMoney = NowMoney + DrawingMoney;System.out.println(Thread.currentThread().getName()+"账户余额为"+account.money);System.out.println(Thread.currentThread().getName()+"手上的现金为"+NowMoney);}}
}

案例3

``

package wang.com.syn;import java.awt.*;
import java.util.ArrayList;
import java.util.List;public class UnsafeList {public static void main(String[] args) {List<String> list = new ArrayList<String>();for (int i = 0; i < 10000; i++) {new Thread(()->{synchronized(list) {list.add(Thread.currentThread().getName());}}).start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}

JUC安全类型集合(CopyOnWriteArrayList)

测试线程安全的类

``

package wang.com.syn;import java.util.concurrent.CopyOnWriteArrayList;public class Juc {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();for (int i = 0; i < 10000; i++) {new Thread(()->{list.add(Thread.currentThread().getName());}).start();}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());}
}

死锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUzGk5Sk-1606532453224)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122160714216.png)]

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\VY$D$E[P6EO7]5DG0XE}F.png)

``

package wang.com.syn;public class DeadLock {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 Lipstick lipstick = new Lipstick();static Mirror mirror = new Mirror();int choice;String girlName;Makeup(int choice, String girlName) {this.choice = choice;this.girlName = girlName;}@Overridepublic void run() {try {makeup();} catch (InterruptedException e) {e.printStackTrace();}}public void makeup() throws InterruptedException {if (choice == 0) {synchronized (lipstick) {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + "口红的锁");synchronized (mirror) {System.out.println(Thread.currentThread().getName() + "镜子的锁");}}}else{synchronized (mirror) {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + "镜子的锁");synchronized (lipstick) {System.out.println(Thread.currentThread().getName() + "口红的锁");}}}}}

Lock锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QmQNpzT2-1606532453225)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122164352524.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-URxkbBj2-1606532453226)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122164417068.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EIqWteXe-1606532453226)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122164451732.png)]

演示代码

``

package wang.com.syn;import java.util.concurrent.locks.ReentrantLock;public class TestLock {public static void main(String[] args) {TestLock2 testLock2 = new TestLock2();new Thread(testLock2,"1").start();new Thread(testLock2,"2").start();new Thread(testLock2,"3").start();}
}
class TestLock2 implements Runnable{private int ticketNums = 10;private final ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {try{lock.lock();while (true){if(ticketNums > 0){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(ticketNums--);}else{break;}}}finally {lock.unlock();}}
}

生产者消费者问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hz7dKJaL-1606532453227)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201124090034272.png)]

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\L4_GMNC@CECD117F9A}SG.png)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8qn8tj5t-1606532453228)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201124090107289.png)]

管程法

synchronized可以阻止并发更新同一个共享资源,实现同步.
但不能来实现不同线程之间的消息传递(即不能实现线程间的通信)

解决方法:
wait() 可以使线程一直等待,直到其它线程通知,与sleep不同,会释放锁.

notifyAll() 可以唤醒同一个对象上所以调用wait()方法的线程,优先级别高的线程优先调度.

``

package wang.com.syn;
//测试:生产者消费者模型,管程法
//生产者 消费者 产品 缓冲区
public class TestPC {public static void main(String[] args) {SynContainer Container = new SynContainer();//让生产者,消费者同时生产new Productor(Container).start();new Consumer(Container).start();}
}
//生产者
class Productor extends Thread{SynContainer Container;public Productor(SynContainer Container){this.Container = Container;}//生产@Overridepublic void run() {for (int i = 0; i < 100; i++) {Container.push(new Chicken(i));System.out.println("生产了"+i+"只鸡");}}
}
//消费者
class Consumer extends Thread{SynContainer Container;public Consumer(SynContainer Container){this.Container = Container;}//消费@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("消费了"+Container.pop().id+"只鸡");}}
}
//产品
class Chicken{int id;//给产品id赋值public Chicken(int id) {this.id = id;}
}
//缓冲区
class SynContainer{//需要一个容器Chicken[] chickens = new Chicken[10];//计数器int count=0;//生产者生产public synchronized void push(Chicken chicken){//如果容器满了,等待消费者消费if(count==chickens.length){//消费者消费,生产者停止try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//否则生产者也生产chickens[count] = chicken;count++;this.notifyAll();}//消费者消费public synchronized Chicken pop(){//判断能否消费if(count==0){//消费者停止,生产者生产try {//让该线程保持等待,直到有其它线程来通知this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果可以消费count--;Chicken chicken = chickens[count];//唤醒该对象所被等待的线程this.notifyAll();return chicken;}
}

信号灯法

``

package wang.com.syn;public class TestPc2 {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("浩哥的幸福生活播放中:");}else{this.tv.play("浩哥打炮中:");}}}
}
//观众观看--消费者
class Watcher extends Thread{TV tv;public Watcher(TV tv){this.tv = tv;}@Overridepublic void run() {this.tv.watch();}
}
//产品--TV
class TV{//节目名String voice;Boolean flag = true;//T时生产者生产,消费者停止//F时生产者停止,消费者观看//演员表演--即生产者生产public synchronized void play(String voice){if(!flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("演员表演了:"+voice);this.voice = voice;this.notifyAll();}//观众观看--即消费者消费public synchronized void watch(){if(flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("观众观看了:"+voice);this.notifyAll();}}

线程池

ExecutorService:真正的线程池接口.常见子类ThreadPoolExecutor

void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable

Futuresubmit(Callabletask):执行任务,有返回值,一般用来执行Callable

void shutdown():关闭连接池

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QtzlKiZf-1606532453228)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\6ZDVMWWKA{~{F@NU][4I%$5.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWDebqm0-1606532453229)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201127105952555.png)]

``

package wang.com.syn;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TestPool {public static void main(String[] args) {//1.创建服务,创建线程池//newFixedThreadPool(10):设置线程池的大小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());}
}

多线程总结

``

package wang.com.syn;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class ThreadNew {public static void main(String[] args) {new MyThread01().start();MyThread02 myThread02 = new MyThread02();new Thread(myThread02).start();FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread03());new Thread(futureTask).start();try {Integer integer = futureTask.get();System.out.println(integer);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}
//1.继承Thread方法
class MyThread01 extends Thread{@Overridepublic void run() {System.out.println("MyThread01");}
}//2.实现Runnable类
class MyThread02 implements Runnable{@Overridepublic void run() {System.out.println("MyThread02");}
}
//3.实现Callable类
class MyThread03 implements Callable<Integer>{@Overridepublic Integer call() throws Exception {System.out.println("MyThread03");return 111;}
}

多线程(Thread的类的运用-Runnable类的使用/多线程的注意点)相关推荐

  1. android实现runnable接口,013 Android多线程-实现Runnable接口

    目录 image 1. 简介 image 2. 使用讲解 2.1 使用步骤 image 特别注意: Java中真正能创建新线程的只有Thread类对象 通过实现Runnable的方式,最终还是通过Th ...

  2. JavaSE基础二十:Java 多线程(线程基础知识、Java 多线程、Java 实现多线程(继承 Thread 类、实现 Runnable 接口、实现 Callable 接口))

    本章目录 1.基础知识准备 2.Java 多线程概述 3.Java 实现多线程 3.1.继承 Thread 类 如何开启新线程 Thread 类常用方法 多线程中的同步 Thread 类同步方法 多线 ...

  3. 多线程中继承Thread 类和实现Runnable 接口的区别

    网上看了很多多线程里继承Thread 类和实现Runnable 接口的区别,大同小异,说下我的观点吧 区别一 创建线程的方式不同: 实现Runnable接口是代理模式,交给Thread()类去star ...

  4. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  5. Java中继承thread类与实现Runnable接口的区别

    Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 在实际应用中, ...

  6. 多线程Runnable类创建多线程

    package com.ajax; //多线程Runnable类创建多线程 public class Example01 {public static void main(String [] args ...

  7. java基础 通过继承Thread类和实现Runnable接口创建线程

    java 创建线程 Java中,线程也是一种对象,但不是任何对象都可以成为线程. 只有实现了Runnable接口或继承了Thread类的对象才能成为线程. 继承Thread类 //格式: class ...

  8. 创建线程的两种方式:继承Thread类和实现Runnable接口

    第一种方式:继承Thread类 步骤:1.定义类继承Thread 2.覆写Threa类的run方法. 自定义代码放在run方法中,让线程运行 3.调用线程的star方法, 该线程有两个作用:启动线程, ...

  9. JAVA重点类 多线程Thread 创建 生命周期 同步

    一.多线程基本概念 1.程序(program)是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 说明:软件安装好了,但是还没跑起来,此时就是静态代码.比如qq,游戏,还 ...

  10. 多线程Thread类创建多线程

    package com.ajax; //多线程Thread类创建多线程 public class Example02 {public static void main(String[] args){n ...

最新文章

  1. task_struct源码
  2. 使用NLTK进行英文分词
  3. 学python的好处-学会python的好处,轻易搭建自己的知乎
  4. codeforce 154C - Double Profiles(hash)
  5. 让jquery easyui datagrid列支持绑定嵌套对象
  6. 基于Dubbo框架构建分布式服务(三)
  7. YbtOJ#20063-[NOIP2020模拟赛B组Day4]古老谜题【统计】
  8. 经典兔子问题python视频_Python练习题 007:兔子生兔子
  9. SQL Server -- 如何书写优雅、漂亮的SQL脚本?
  10. python sqlalchemy core
  11. 安装ruby1.9.3
  12. PHP 5.6 已结束安全支持,你升级到 PHP 7 系列了吗?
  13. Win10离线安装choco方案
  14. Word处理控件Aspose.Words功能演示:使用 Java 将 Word 文档转换为 Markdown
  15. iOS关于图片点到像素转换之杂谈
  16. java项目如何发送邮件
  17. linux工具之jq
  18. 【无标题】刘易远:做事必须要脚踏实地
  19. android-设置屏幕壁纸
  20. redis三个定时监控任务和主观下线、客观下线

热门文章

  1. golang 读写 xlsx 文件
  2. js导入xlsx文件
  3. LeetCode——592.分数加减运算
  4. DDR3/4 内存模组(SIMM DIMM RIMM ,SO-DIMM UDIMM RDIMM LRDIMM区别)
  5. bin、hex、elf、axf文件的区别
  6. 基于OpenCV的多目标动态检测与跟踪
  7. 利用mysql客户端查询UCSC数据库
  8. Google地图实时轨迹
  9. 最详细iOS打包流程
  10. 计算机开题报告课题来源,开题报告课题来源该怎么写