day15_thread

本文详细介绍了Java中的线程概念,包括进程与线程的区别,线程的创建和执行,以及多线程原理。此外,还探讨了垃圾回收机制,如何启动和管理线程,以及线程同步的方法,如同步代码块、同步方法和wait/notify机制。
摘要由CSDN通过智能技术生成

1 概念

	 *1 线程的概念
	 *  进程:电脑中正在运行的程序
	 *  线程:正在运行的程序中正在执行的代码块
	 *        线程是进程的基本单位/执行单元
	 *        进程为线程提供执行空间
	 *  实例: 正在生产的工厂---进程
	 *        正在生产的工厂中正在运行的流线线---线程
	 *  多线程/线程并发:一个程序中有多个代码块同时执行

2 垃圾回收机制

	 *2 垃圾回收机制:
	 *   jvm会不定时的启动垃圾回收器对象 ,垃圾回收器会根据对象是否存在更多引用
	 *   来判断此对象是否是垃圾 如果是垃圾就调用对象的finalize方法 来销毁对象 释放内存
	 *   程序员可以通过System.gc()来主动启动垃圾回收器
	 *   
	 *   专门有一个线程:垃圾回收的线程  
	 *   和主(main---执行main方法中的代码)线程是不同的线程
package day15_thread;

public class Demo01 {
	public static void main(String[] args) {
		for (int i = 0; i <20; i++) {
			new Test01();
		}
		//启动了垃圾回收器:::
		System.gc();
		
		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < 100; j++) {
				if(i%5==0&&j==10) {
					System.out.println("主方法的代码:::i="+i);
				}
			}
		}
	}
	public static Object hehe() {
		Object obj=new Object();
		return obj;
	}
}
class Test01{
	private static int n=0;
	public final int num;
	{n++;num=n;System.out.println("第"+num+"个对象被创建了!!!");}
	public String toString() {
		return "Test01 [num=" + num + "]";
	}

	@Override
	protected void finalize() throws Throwable {
		System.out.println(this.num+":::finalize方法被调用!::::");
		super.finalize();
	}
}

在这里插入图片描述

3 多线程原理

     *多线程原理:cpu在同一个时间轮片(时间单位:大概20hm)内只执行一个线程的代码 
	 *            时间轮片到期 就在等待的多个线程之间进行随机切换

4 创建线程方式1

package day15_thread;

public class Demo02CreateThread {
	/*
	 * 一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例
	 * 方式1:继承Thread 重写run方法
	 * 1: 创建Thread子类
	 * 2:重写run方法
	 * 3:创建线程对象
	 * 4:启动线程(start方法)
	 * */
	public static void main(String[] args) {
		  //3:创建线程对象
		  MyThread021 mt1=new MyThread021();
		  //4:启动线程(start方法):::当线程对象的start方法调用时 虚拟机会为此线程在内存中开辟执行空间 然后执行其run方法中的代码
		  mt1.start();
		
		   for (int i = 0; i < 50; i++) {
			  Thread t=Thread.currentThread();//当前线程::执行此代码的线程
			  System.out.println(t.getName()+"+++++++++++++++++++i="+i);
			  //当前线程休眠
			  try {Thread.sleep(30);} catch (Exception e) {throw new RuntimeException(e);} 
		   }
	}
}
// 1: 创建Thread子类
class MyThread021 extends Thread{
	//2:重写run方法::线程任务:::当前线程要执行的代码
	public  void run() {
	   for (int i = 0; i < 50; i++) {
		  Thread t=Thread.currentThread();//当前线程::执行此代码的线程
		  System.out.println(t.getName()+"-----i="+i);
		  //当前线程休眠
		  try {Thread.sleep(30);} catch (Exception e) {throw new RuntimeException(e);} 
	   }
	}
}

5 Thread的常用方法

	 * Thread类的方法:
	 * 构造方法:
	 *    Thread() :线程名字是默认的:Thread-index
	 *    Thread(String name) :指定线程名字
	 *    Thread(Runnable target) :
	 *    Thread(Runnable target, String name) 
	 * 普通方法:
	 *    String getName()  :获取线程名字
	 *    void setName(String name)  :设置线程名字
	 *    static Thread currentThread() :获取当前线程对象
	 *    void run()  :封装线程任务:线程启动 jvm自动调用线程的run方法
	 *    void start()  :线程启动:jvm会在内存中为当前线程开辟执行空间 执行其线程任务
	 *    static void sleep(long millis) :线程休眠

6 练习

三个线程打印不同的字符:三个类

package day15_thread;

public class LianXi01 {
	public static void main(String[] args) {
		  //3 创建线程对象
		MyThread01SZ sz1=new MyThread01SZ();sz1.setName("数字::");
		MyThread01XX sz2=new MyThread01XX();sz2.setName("xiaoxie::::");
		MyThread01DX sz3=new MyThread01DX();sz3.setName("DAXIE::::::::::");
		//4 启动线程
		sz1.start();sz2.start();sz3.start();
		
	}
}
//* 练习1:三个线程:线程a打印随机50个0-9的数字  线程b打印随机50个大写 线程c打印随机50个小写
//*       尽量交替
class MyThread01SZ extends Thread{
	  public void run() {
		   String name=Thread.currentThread().getName();
		   for (int i = 0; i < 50; i++) {
			    char c=(char)(Math.random()*10+'0');
			    System.out.println(name+"::::"+c);
			    try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		   }
	  }
}
class MyThread01XX extends Thread{
	  public void run() {
		   String name=Thread.currentThread().getName();
		   for (int i = 0; i < 50; i++) {
			    char c=(char)(Math.random()*26+'a');
			    System.out.println(name+"::::"+c);
			    try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		   }
	  }
}
class MyThread01DX extends Thread{
	  public void run() {
		   String name=Thread.currentThread().getName();
		   for (int i = 0; i < 50; i++) {
			    char c=(char)(Math.random()*26+'A');
			    System.out.println(name+"::::"+c);
			    try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		   }
	  }
}

三个线程打印不同的字符:一个类

package day15_thread;

public class LianXi02 {
	/*
	 * 三个线程定义基本一样:考虑使用一个类来描述三个线程
	 * 把不同的地方定义为变量:随机的范围+随机的起始字符
	 * 在run方法需要获取这两个变量:方法可以使用的变量:参数列表+成员变量
	 * 方法参数不可取:::run方法是重写  方法声明不能更改
	 * 只能把两个变量设置为成员变量
	 * 
	 * 模拟五个学生同一个老师分别交自己的4份作业
	 * 
	 * 模拟4个窗口 卖同一个火车的100张票:票号从100到1
	 * */
	public static void main(String[] args) {
		  //3 创建线程对象
		MyThread01 sz1=new MyThread01(10,'0');sz1.setName("数字::");
		MyThread01 sz2=new MyThread01(26,'a');sz2.setName("xiaoxie::::");
		MyThread01 sz3=new MyThread01(26,'A');sz3.setName("DAXIE::::::::::");
		//4 启动线程
		sz1.start();sz2.start();sz3.start();
	}
}
//* 练习1:三个线程:线程a打印随机50个0-9的数字  线程b打印随机50个大写 线程c打印随机50个小写
//*       尽量交替
class MyThread01 extends Thread{
	  int fw;
	  char startChar;
	  MyThread01(int fw,char startChar){this.fw=fw;this.startChar=startChar;}
	  public void run() {
		   String name=Thread.currentThread().getName();
		   for (int i = 0; i < 50; i++) {
			    char c=(char)(Math.random()*fw+startChar);
			    System.out.println(name+"::::"+c);
			    try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		   }
	  }
}

7 创建线程方式2

步骤

public class Demo04CreateThread {
    /*
     * 声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动
     * 创建线程方式2:实现Runnable接口 实现run方法
     * 1 创建 Runnable 接口的实现类
     * 2 实现run方法
     * 3 创建实现类对象
     * 4 创建Thread线程对象 并通过构造方法参数列表给实现类关联( Thread(Runnable target) :)
     * 5 开启线程
     *  
     * */
	public static void main(String[] args) {
		//3 创建实现类对象:::对线程任务的封装
		MyImp1 m1=new MyImp1();
		//4 创建Thread线程对象 并通过构造方法参数列表给实现类关联
		Thread t1=new Thread(m1, "线程11");
		Thread t2=new Thread(m1, "线程2222");
		//5 启动线程
		t1.start();//jvm调用m1.run()
		t2.start();//jvm调用m1.run()
		
		//t1中有几个run方法
		
		Thread t3=new Thread( "线程333");
		t3.start();//jvm调用t3.run()

	}


}
//1 创建 Runnable 接口的实现类
class MyImp1 implements Runnable {
	//2 实现run方法
	public void run() {
		for (int i = 0; i <20; i++) {
			 System.out.println(Thread.currentThread().getName()+":::"+i+":::"+(int)(Math.random()*100));
			 try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
}

模拟

jvm怎么智能判断 运行Thread类的run方法还是运行Thread类关联的Runnable的run方法
class MyThreadDemo{//类似于Thread
	private MyRunnableDemo r;
	MyThreadDemo(){}
	MyThreadDemo(MyRunnableDemo r){this.r=r;}
	public void run() {
		System.out.println("Thread类的run方法!!!");
	}
	public void start() {
		//虚拟机给当前线程对象在内存中分配执行空间
		//运行当前线程的线程任务:::实现类的run/当前类的run
		if(r!=null) {
			r.run();
		}else {
			this.run();
		}
	}
}
interface MyRunnableDemo{//类似于Runnable接口
	public void run();
}

比较

     * 两种创建线程的方式之间作比较:第二种方式更优:
     * 1 :java只支持类与类的单继承 方式1继承了Thread 无法再扩展
     *                           方式2实现Runnable接口 不影响继承其他类 还可以再扩展
     * 2 : 实现Runnable接口的实现类对象 是对线程任务的封装  符合java完全面向对象的思想

8 练习

交作业

package day15_thread;

public class LianXi03 {
     //5个学生给同一个老师交4份作业
	public static void main(String[] args) {
		Teacher03 tt=new Teacher03();
		StudentImp imp1=new StudentImp();
		StudentImp imp2=new StudentImp();
		StudentImp imp3=new StudentImp();
		StudentImp imp4=new StudentImp();
		StudentImp imp5=new StudentImp();
		imp1.t=tt;imp2.t=tt;imp3.t=tt;imp4.t=tt;imp5.t=tt;
		Thread t11=new Thread(imp1, "张三");
		Thread t12=new Thread(imp2, "张三丰");
		Thread t13=new Thread(imp3, "张三太郎");
		Thread t14=new Thread(imp4, "三");
		Thread t15=new Thread(imp5, "3");
		
		t11.start();t12.start();t13.start();t14.start();t15.start();

	}
}
class Teacher03{
	//static int num;
	int num;
}
//每个学生对应一个线程
class StudentImp implements Runnable{
	Teacher03 t;
	//Teacher03 teacher=new Teacher03();//每个实现类对象对应一个老师::5个线程对象使用同一个实现类对象 合理
	public void run() {
		//Teacher03 teacher=new Teacher03();//每个线程对应一个老师
		for (int i = 1; i <=4; i++) {
			 System.out.println(Thread.currentThread().getName()+":::::正在提交作业::"+i);
			 //Teacher03 teacher=new Teacher03();//每次都提交给不同的老师
			 t.num++;
			 try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
			 System.out.println("老师的作业本书是:::"+t.num);
		}
	}
}

卖票

package day15_thread;

public class LianXi04 {
    //模拟4个窗口 卖同一个火车的100张票:票号从100到1
	public static void main(String[] args) {
		WindowImp imp=new WindowImp();
		imp.t=new Train();
		new Thread(imp,"窗口1111").start();
		new Thread(imp,"窗口11112222").start();
		new Thread(imp,"窗口111133333333").start();
		new Thread(imp,"窗口1111444444444444").start();

	}
}
class Train{
	int num=100;
}
class WindowImp implements Runnable{
	Train t;
	public void run() {
		while(t.num>0) {
			 try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
			 System.out.println(Thread.currentThread().getName()+":::::卖票::票号是:::"+t.num);
			 t.num--;
		}
	}
}

9 join

join

package day15_thread;

public class Demo05Join {
	/*
	 * Thread类的 void join()方法:等待该线程终止。
	 * 在A线程任务中调用B线程对象的join方法::A线程会一致处于等待状态(失去cpu随机的权限)
	 * 直到B线程执行完毕 A线程才能获取cpu的执行权
	 * */
	public static void main(String[] args) {
		Demo05Imp1 imp1=new Demo05Imp1();
		Thread t1=new Thread(imp1, "线程1");
		Thread t2=new Thread(new Demo05Imp2(), "线程2222");
		imp1.t=t2;//指定t1线程需要等待的线程对象
		t1.start();
		t2.start();
		for (int i = 0; i < 50; i++) {
			 //当前线程打印到5时 等待另外一个线程执行完毕 当前线程再执行
			 int n=(int)(Math.random()*10);
			 System.out.println(Thread.currentThread().getName()+":::::::"+i+"::::::"+n);
			 try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		}
		
	}
}
class Demo05Imp1  implements Runnable{
	Thread t;//定义引用记录需要等待的线程对象
	public void run() {
		for (int i = 0; i < 50; i++) {
			 //当前线程打印到5时 等待另外一个线程执行完毕 当前线程再执行
			 int n=(int)(Math.random()*10);
			 System.out.println(Thread.currentThread().getName()+":::"+i+":::"+n);
			 //调用t2.join()方法
			 if(n==5) {
				 try {t.join();} catch (Exception e) {throw new RuntimeException(e);}
			 }
			 try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
}
class Demo05Imp2  implements Runnable{
	public void run() {
		for (int i = 0; i < 50; i++) {
			 System.out.println(Thread.currentThread().getName()+":::::"+
                                i+"::::::"+(int)(Math.random()*10+10));
			 try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
}

join死锁

两个线程互相调用对方的join方法
package day15_thread;

public class Demo06JoinDieLock {
	public static void main(String[] args) {
		MyPrintImp t1=new MyPrintImp();
		MyPrintImp t2=new MyPrintImp();
		t1.t=t2;
		t2.t=t1;
		t1.joinChar='0';
		t2.joinChar='5';
		t1.setName("线程1号");
		t2.setName("线程2222222222222号");
		t1.start();
		t2.start();
	}
}
class MyPrintImp extends Thread{
	//定义引用记录要等待的线程
	Thread t;
	//定义变量记录要等待的字符
	char joinChar;
	public void run() {
		for (int i = 1; i <= 50; i++) {
			try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
			char c=(char)(Math.random()*10+'0');
			System.out.println(Thread.currentThread().getName()+":::"+i+":::::"+c);
			if(t!=null&&c==joinChar) {
				try {t.join();} catch (Exception e) {throw new RuntimeException(e);}
			}
		}
	}
}

10 线程同步

线程安全问题

     * 分析:出现情况:1 票号重复 2 有负票存在
	 * 票号重复的原因:
	 *   a线程在打印完num(100)后  没有立刻执行num--
	 *   cpu的执行权随机给了另外一个线程b b线程也是先打印num(100) b
	 * 
	 * 
	 * 负票的存在原因:
	 *    假设num=1并且此时4个线程都到达while(num>0)位置
	 *    a线程判断num>0成立 进来后需要休眠  此时时间轮片到期 随机到b线程 
	 *    b线程判断num>0成立 进来后需要休眠  假设此时时间轮片也到期 随机到c线程 
	 *    c线程判断num>0成立 进来后需要休眠  假设此时时间轮片还到期 随机到d线程 
	 *    d线程判断num>0成立 也进来
	 *    后期打印:num=1 0 -1 -2 四张票被卖
	 * 
	 * 多线程中:由于多个线程操作同一个数据 出现前后数据不一致 结果无法预期的现象---线程安全问题
	 * 线程安全问题前提条件:
	 *      1 必须时多线程
	 *      2 必须有共享数据
	 *      3 必须有多个语句操作共享数据:一个线程在多个语句操作共享数据期间 别的线程对共享数据进行了修改

同步代码块

package day16_thread_xml;

public class Demo01Sync {
	/*
	 * 通过synchronized 同步代码块 来解决线程安全问题:在一个线程使用共享数据时 其他线程如果也要使用共享数据 就等待
	 * 格式: 
	 *      synchronized(任意类型的对象:锁对象){
	 *          当前线程操作共享数据的所有代码
	 *      }
	 * 注意1:锁对象:就是个标志 哪个线程拿到锁对象 哪个线程就有对共享数据的使用权::必须唯一
	 * 注意2:同步代码块 必须包含 当前线程操作共享数据的所有代码
	 * 
	 * */

	public static void main(String[] args) {
		// 模拟4个窗口 卖同一个火车的100张票:票号从100到1
		WindowImp imp1 = new WindowImp();
//		WindowImp imp2 = new WindowImp();
//		WindowImp imp3 = new WindowImp();
//		WindowImp imp4 = new WindowImp();
		Train t=new Train();
		imp1.t = t;
//		imp2.t = t;imp3.t = t;imp4.t = t;
//		Object o=new Object();
//		imp1.obj=o;imp2.obj=o;imp3.obj=o;imp4.obj=o;
		new Thread(imp1, "窗口1111").start();
		new Thread(imp1, "窗口11112222").start();
		new Thread(imp1, "窗口111133333333").start();
		new Thread(imp1, "窗口1111444444444444").start();
		

	}
}

class Train {
	int num = 100;
}

class WindowImp implements Runnable {
	Train t;
	//Object  obj;
	public void run() {
			while (true) {
				synchronized (t) {//锁对象唯一
					if(t.num<=0) {//num=1
						break;
					}
					try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
					System.out.println(Thread.currentThread().getName() + ":::::卖票::票号是:::" + t.num);
					try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
					t.num--;
			    }
				try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
		    }
	}
}

同步代码块实现死锁

通过同步代码块实现死锁:两个同步代码块嵌套,两个线程的内外锁交替
package day16_thread_xml;

public class Demo02SyncDieLock {
     //通过同步代码块实现死锁:两个同步代码块嵌套,两个线程的内外锁交替
	public static void main(String[] args) {
		MyThread02 t1=new MyThread02();
		MyThread02 t2=new MyThread02();
		Object a=new Object();
		Object b=new Object();
		t1.wai=a;t1.nei=b;
		t2.wai=b;t2.nei=a;
		t1.setName("线程1号::");
		t2.setName("线程2号:::::");
		t1.start();
		t2.start();
	}
}
class MyThread02 extends Thread{
	  Object wai,nei;
	  public void run() {
		  while(true) {
			  synchronized (wai) {
				   System.out.println(Thread.currentThread().getName()+"拿到其外锁+++++"+wai);
				   synchronized (nei) {
					    System.out.println(Thread.currentThread().getName()+"拿到其内锁+++++++++"+nei);
				   }
				   System.out.println(Thread.currentThread().getName()+"释放内锁---------"+nei);
			  }
			  System.out.println(Thread.currentThread().getName()+"释放外锁-----"+wai);
			  
		  }
		
	  }
}

11 wait和notify,notifyAll

package day16_thread_xml;

public class Demo03WaitNotify {
	/*
	 * 
	 * Object类的方法:void  wait();      当前线程等待
	 * Object类的方法:void  notify();    随机唤醒一个处于等待状态的线程
	 * Object类的方法:void  notifyAll();    唤醒所有处于等待状态的线程
	 * 注意:他们三个都是锁对象的方法
	 * 
	 * 场景:做烧饼和吃烧饼:::做完就吃 吃完再做
	 * 线程:吃烧饼的线程  做烧饼的线程
	 * 共享数据:烧饼
	 * */

	public static void main(String[] args) {
		ShaoBing s=new ShaoBing();
		
		CreateShb c=new CreateShb();c.setName("武大郎");
		CreateShb c2=new CreateShb();c2.setName("武松");
		EatShb e=new EatShb();e.setName("西门庆");
		EatShb e2=new EatShb();e2.setName("潘金莲");
		c.shb=s; e.shb=s;c2.shb=s; e2.shb=s;
		
		c.start(); e.start();c2.start(); e2.start();
	}
}
//烧饼类
class ShaoBing{
	int num;//定义一个变量 记录当前烧饼的编号 
	boolean b=false;//记录当前是否有烧饼
}
//做烧饼的线程
class CreateShb extends Thread{
	ShaoBing shb;//定义引用记录烧饼对象
	 public void run() {
		  while(true) {
			  synchronized (shb) {
				  if(!shb.b) {
					  shb.num++;
					  System.out.println(Thread.currentThread().getName()+"开始做烧饼::"+shb.num);
					  try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
					  System.out.println(Thread.currentThread().getName()+"烧饼做好了::"+shb.num); 
					  shb.b=true;//有烧饼了
					  //提醒吃烧饼的线程可以吃了
					  //shb.notify();//随机唤醒一个 正在等待的线程
					  shb.notifyAll();//唤醒所有正在等待的线程
				  }
				  //当前线程等待
				  try {shb.wait();} catch (Exception e) {throw new RuntimeException(e);}
			  }
			  try {Thread.sleep(500);} catch (Exception e) {throw new RuntimeException(e);}
		  }
	 }
}
//吃烧饼的线程
class EatShb extends Thread{
	 ShaoBing shb;//定义引用记录烧饼对象
	 public void run() {
		  while(true) {
			  synchronized (shb) {
				  if(shb.b) {
					  System.out.println(Thread.currentThread().getName()+"开始吃烧饼:::::"+shb.num);
					  try {Thread.sleep(10);} catch (Exception e) {throw new RuntimeException(e);}
					  System.out.println(Thread.currentThread().getName()+"烧饼吃完了:::::"+shb.num);
					  shb.b=false;
					  //提醒做烧饼的线程可以做了
					  //shb.notify();//随机唤醒一个 正在等待的线程
					  shb.notifyAll();//唤醒所有正在等待的线程
				  } 
				  //当前线程等待
				  try {shb.wait();} catch (Exception e) {throw new RuntimeException(e);} 
			  }
			  try {Thread.sleep(2);} catch (Exception e) {throw new RuntimeException(e);}
		  }
	 }
}

12 同步方法

同步实例方法

package day16_thread_xml;

public class Demo04SyncMethod {
    /*同步方法:如果一个方法的整个方法体 都要求同步:可以把次方法定义为同步方法
     * 实例同步方法的锁对象是this
     * */
	public static void main(String[] args) {
		Person p=new Person();
		SetThread set=new SetThread();set.p=p;
		PrintThread print=new PrintThread();print.p=p;
		set.start();
		print.start();

	}
}
class Person{
	String name;
	char sex;
	//如果一个方法的整个方法体 都要求同步:可以把次方法定义为同步方法
	public synchronized void set() {
		if(Math.random()<0.5) {
			this.sex='女';
			this.name="rose"+(int)(Math.random()*100+1);
		}else {
			this.sex='男';
			this.name="张三"+(int)(Math.random()*100+1);
		}
	}
}
//给属性赋值线程
class SetThread extends Thread{
	Person p;
	public void run() {
		while(true) {
			//synchronized (p) {
			//	p.set();
			//}
			if(Math.random()>0.5) {
				p.set();//同步方法
			}else {
				synchronized (p) {//同步代码块
					if(Math.random()<0.5) {
						p.sex='女';
						p.name="rose"+(int)(Math.random()*100+1);
					}else {
						p.sex='男';
						p.name="张三"+(int)(Math.random()*100+1);
					}
				}
			}
			try {Thread.sleep(100);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
}
//打印线程
class PrintThread extends Thread{
	Person p;
	public void run() {
		while(true) {
			synchronized (p) {
				System.out.println(p.sex+":::"+p.name);
				try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
			}
			try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
}

同步静态方法

package day16_thread_xml;

public class Demo04SyncMethod2 {
    /*同步方法:如果一个方法的整个方法体 都要求同步:可以把次方法定义为同步方法
     * 实例同步方法的锁对象是this
     * 静态同步方法的锁对象是当前类的字节码文件对象
     * */
	public static void main(String[] args) {
		Person2 p=new Person2();
		SetThread2 set=new SetThread2();set.p=p;
		PrintThread2 print=new PrintThread2();print.p=p;
		set.start();
		print.start();

	}
}
class Person2{
	String name;
	char sex;
}
//给属性赋值线程
class SetThread2 extends Thread{//SetThread2.class
	Person2 p;
	public void run() {
		while(true) {
			if(Math.random()>0.5) {
				set(p);//静态同步方法
			}else {
				synchronized (SetThread2.class) {//同步代码块
					if(Math.random()<0.5) {
						p.sex='女';
						try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
						p.name="rose"+(int)(Math.random()*100+1);
					}else {
						p.sex='男';
						try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
						p.name="张三"+(int)(Math.random()*100+1);
					}
				}
			}
			try {Thread.sleep(50);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
	public static synchronized void set(Person2 p) {
		if(Math.random()<0.5) {
			p.sex='女';
			try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
			p.name="rose"+(int)(Math.random()*100+1);
		}else {
			p.sex='男';
			try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
			p.name="张三"+(int)(Math.random()*100+1);
		}
	}
}
//打印线程
class PrintThread2 extends Thread{
	Person2 p;
	public void run() {
		while(true) {
			synchronized (SetThread2.class) {
				System.out.println(p.sex+":::"+p.name);
				try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
			}
			try {Thread.sleep(20);} catch (Exception e) {throw new RuntimeException(e);}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值