Thread 的生命周期

一、实现Runnable接口方式

1、在 run 方法中使用 synchronized

/*** 例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式* 1.问题:卖票过程中,出现了重票、错票 -->出现了线程的安全问题* 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。* 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,*  其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。* 4.在Java中,我们通过同步机制,来解决线程的安全问题。*      方式一:同步代码块*          synchronized(同步监视器){*             //需要被同步的代码*          }*          说明:*              1.操作共享数据的代码,即为需要被同步的代码。  -->不能包含代码多了,也不能包含代码少了。*              2.共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。*              3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。*          要求:多个线程必须要共用同一把锁。*          补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。*      方式二:同步方法。*          如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。* 5.同步的方式,解决了线程的安全问题。---好处*  操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。 ---局限性*/
class TicketWindow implements Runnable {private int ticket = 100;//  Object obj = new Object();//正确@Overridepublic void run() {//  Object obj = new Object();//错误while (true) {//            synchronized (obj){synchronized (this) {//此时的this:唯一的Window1的对象if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;} else {break;}}}}
}public class Main1 {public static void main(String[] args) {TicketWindow ticketWindow = new TicketWindow();Thread t1 = new Thread(ticketWindow);Thread t2 = new Thread(ticketWindow);Thread t3 = new Thread(ticketWindow);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

2、使用syncronized方法

/*** 使用同步方法解决实现Runnable接口的线程安全问题* 关于同步方法的总结:* 1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。* 2. 非静态的同步方法,同步监视器是:this* 静态的同步方法,同步监视器是:当前类本身*/
class TicketWindow3 implements Runnable {private int ticket = 100;@Overridepublic void run() {while (true) {show();}}private synchronized void show() {//相当于同步监视器是:this//synchronized (this){if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;}//}}
}public class Main3 {public static void main(String[] args) {TicketWindow3 w = new TicketWindow3();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

二、继承Thread类方式

1、在 run 方法中使用 synchronized

/*** 使用同步代码块解决继承Thread类的方式的线程安全问题* 例子:创建三个窗口卖票,总票数为100张.使用继承Thread类的方式* 说明:在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。*/
class TicketWindow2 extends Thread {private static int ticket = 100;private static Object obj = new Object();@Overridepublic void run() {while (true) {//          synchronized (obj){//正确的方式1:使用 static 的 obj 作为 synchronized 锁synchronized (TicketWindow2.class) {//正确的方式2:因为Class clazz = TicketWindow4.class, TicketWindow4.class只会加载一次
//          synchronized (this){//错误的方式:this代表着t1,t2,t3三个对象if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getName() + ":卖票,票号为:" + ticket);ticket--;} else {break;}}}}
}public class Main2 {public static void main(String[] args) {TicketWindow2 t1 = new TicketWindow2();TicketWindow2 t2 = new TicketWindow2();TicketWindow2 t3 = new TicketWindow2();t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

2、使用syncronized静态方法

/*** 使用同步方法处理继承Thread类的方式中的线程安全问题*/
class TicketWindow4 extends Thread {private static int ticket = 100;@Overridepublic void run() {while (true) {show();}}private static synchronized void show() {   //正确:使用静态方法,相当于同步监视器:TicketWindow4.class,是当前类本身
//  private synchronized void show(){           //错误:使用非静态方法,相当于同步监视器:t1,t2,t3,是三个不同的对象当做锁if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;}}
}public class Main4 {public static void main(String[] args) {TicketWindow4 t1 = new TicketWindow4();TicketWindow4 t2 = new TicketWindow4();TicketWindow4 t3 = new TicketWindow4();t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

三、线程安全的懒汉式单例模式

/*** 使用同步机制,将单例模式中的'懒汉式'改写为线程安全的*/
public class Bank {private static Bank bankInstance = null;public static Bank getBankInstance() {if (null == bankInstance) {//进入synchronized前先判断,效率更高synchronized (Bank.class) {if (null == bankInstance) {bankInstance = new Bank();}}}return bankInstance;}
}

四、死锁问题示例

public class LockedTest {public static void main(String[] args) {StringBuffer sb1 = new StringBuffer();StringBuffer sb2 = new StringBuffer();new Thread() {@Overridepublic void run() {synchronized (sb1) {//拿到sb1锁sb1.append("a");sb2.append("b");System.out.println("拿到sb1锁");try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("等待sb2锁");synchronized (sb2) {sb1.append('1');sb2.append('2');System.out.println("sb1=" + sb1);System.out.println("sb2=" + sb2);}}}}.start();new Thread(new Runnable() {//匿名Runnable对象,实现Runnable接口@Overridepublic void run() {synchronized (sb2) {System.out.println("拿到sb2锁");sb1.append("c");sb2.append("d");System.out.println("等待sb1锁");synchronized (sb1) {sb1.append('3');sb2.append('4');System.out.println("sb1=" + sb1);System.out.println("sb2=" + sb2);}}}}).start();}
}

输出

拿到sb1锁
拿到sb2锁
等待sb2锁

【Java多线程】实现Runnable接口方式 / 继承Thread类方式;使用synchronized锁实现线程安全;线程安全的懒汉式单例模式;死锁问题示例相关推荐

  1. 实现Runnable接口和继承Thread类之间的区别

    在Java语言中,我们都知道,有两种创建线程的方式,一中是使用Runnable接口,另一种是使用Thread类. public class DemoRunnable implements Runnab ...

  2. java多线程------实现Runnable接口创建多进程,实现资源共享

    //实现Runnable接口创建多进程,实现资源共享 package xian_cheng;public class Example05 {public static void main(String ...

  3. 多线程模拟火车站卖票-继承Thread类

    public class Demo2_Snschronized { public static void main(String[] args) { // TODO Auto-generated me ...

  4. 多线程的创建方式---继承Thread和实现Runnable

    继承Thread类创建多线程 1 package cn.ftf.thread; 2 /** 3 * 多线程实现方式一 继承Thread实现多线程,继承Thread,重写run方法 4 * @autho ...

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

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

  6. java线程如何继承,java多线程(一)之继承Thread类

    一.概述 进程:正在执行的应用程序 线程:进程的执行单元,执行路径 单线程:一个应用程序只有一条执行路径 多线程:一个应用程序有多条执行路径 二.两种实现方式, 下面为第一种方式: 继承Thread类 ...

  7. 继承Thread类实现多线程简单实例

    继承Thread类实现多线程简单实例 文章目录 继承Thread类实现多线程简单实例 一.多线程的意义 二.多线程的创建 三.代码 一.多线程的意义 1.为什么要使用多线程 (a)提高用户体验或者避免 ...

  8. extends thread java_java学习之- 线程继承Thread类

    标签(空格分隔): 线程 在java.lang包中有个Thread子类,大家可以自行查阅文档,及范例: 如何在自定义的代码中,自定义一个线程呢? 1.通过对api的查找,java已经提供了对线程这类事 ...

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

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

最新文章

  1. 在Stack Overflow如果语言有问题,请写以下英文
  2. Python Coding Guidelines
  3. 《Linux菜鸟入门》认识linux系统
  4. Php中如何记录本报时间,详细讲解PHP的日期时间函数date()
  5. mysql c contor_Python之那些好玩的图画
  6. 海信集团:通过数据来驱动企业的管理,让数据真正成为生产力
  7. kmeans聚类算法matlab_KMeans聚类算法详解
  8. shell win10 改成cmd_win10系统必做优化,让你的电脑告别卡顿,运行速度至少提升20%...
  9. idea 导入maven项目
  10. IO 理论 SOCK理论
  11. linux中kvm配置文件,linux操作系统内配置vlan+kvm虚拟机
  12. 基于51单片机ADC0808自动数字电压表仿真数码管显示
  13. 关于材料设计vector矢量图形
  14. Unity遮罩简单复刻2D平台《Unbound: Worlds Apart》游离于世界之海的双重世界效果
  15. 嵌入式软件设计(freertos使用)
  16. android添加浮动组件,添加悬浮操作按钮  |  Android 开发者  |  Android Developers
  17. 5G时代到底会发生什么
  18. 转:程序员应该怎样去学习和掌握计算机英语呢?
  19. ”excel 无法粘贴信息,原因是复制区域与粘贴区域形状不同“解决方法
  20. CA-MKD:置信多教师知识蒸馏

热门文章

  1. python的映射_Python学习:映射函数(map)和函数式编程工具(filter和reduce)
  2. 力扣题458:可怜的小猪
  3. MySQL主主复制 外键_MySQL 组复制介绍
  4. 利用栈进行程序的括号匹配
  5. 自然数幂和取模问题进一步探究
  6. 替换系统wsock32.dll,实现封包拦截
  7. Chromium Android开发的Eclipse配置
  8. 用Python实现冒泡排序
  9. 搞定 Go 语言,不会这些可不行
  10. 一些实用的编程模式 | Options模式