JAVA进阶版:多线程

1. 实现多线程的2种方式

(1)方式1:继承java.lang.Thread

package javase.jingjie.多线程;
/**
 * 在java语言中实现多线程的第一种方式:
 *       第一步: 继承java.lang.Thread;
 *       第二步: 重写run方法
 *   
 * 三个知识点:1.如何定义线程?   2.如何创建线程?   3.如何启动线程?
 * */
import java.lang.*;
public class DuoXianCheng01 {

	public static void main(String[] args) {
		// 创建线程
		Thread t=new Processor();

		//启动
		//这段代码执行瞬间结束,告诉JVM再分配一个新的栈给t线程
		//run不需要程序员手动调用,系统线程启动之后自动调用run方法
		t.start();
		
		//t.run();//这是普通方法调用,这样做程序只有一个线程,run方法结束之后,下面程序才能继续执行。
		
		//这段代码在主线程中运行
		for(int i=0;i<10;i++) {
			System.out.println("main-->"+i);
		}
		/*
		 * 有了多线程之后,main方法结束只是主线程栈中没有方法栈帧了。
		 * 但是其他线程或者其他栈中还有栈帧。
		 * main方法结束,程序可能还在运行。
		 * */
	}
}
//定义一个线程
class Processor extends Thread{
	//重写run方法
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println("run-->"+i);
		}
	}
}

(2)方式2:写一个类实现java.lang.Runnable;接口

package javase.jingjie.多线程;
/**
 * java中实现线程的第二种方法:
 * -----第一步:写一个类实现java.lang.Runnable;接口
 * -----第二步:实现run方法
 * */
import java.lang.*;
public class DuoXianCheng02 {

	public static void main(String[] args) {
		// 创建线程
		Thread t=new Thread(new Processor01());//Runnable t=new Processor01();
	
		t.start();//启动
	}

}
class Processor01 implements Runnable{
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println("run-->"+i);
		}
	}
}

2. 7种线程的简单操作

(1) 三个方法:Thread.currentThread(), t.setName(""), t.getName()

package javase.jingjie.多线程;
/**
 * 三个方法:
 *    1.获取当前线程对象Thread.currentThread();currentThread()是一个静态方法,用类名去调用
 *    2.给线程起名 t.setName( " 名字")
 *    3.获取线程的名字 t.getName("");
 *    
 *     多线程的结果:是不断变化的,哪个线程(主线程main,t1,t2)先抢到时间片,先启动运行该线程
 *     main
   t2线程
   Thread-0
   
   main
Thread-0
t2线程
 *     
 * */
public class DuoXianCheng03 {

	public static void main(String[] args) {
		// 获取当前线程对象,currentThread()是一个静态方法,用类名去调用
		Thread t=Thread.currentThread();//t保存的内存地址指向的线程是“主线程对象”
		
		//获取线程的名字
		System.out.println(t.getName());//main
		
		//创建线程,启动线程
		Runnable p=new Processor02(); 
		Thread t1=new Thread(p);
		t1.start();
		
		Thread t2=new Thread(new Processor02());
		//给t2线程起名字
		t2.setName("t2线程");
		//启动线程
		t2.start();
	}

}
class Processor02 implements Runnable{
	public void run() {
		//当哪个(t1,t2)线程启动时,t就代表谁
		Thread t=Thread.currentThread();//t保存的内存地址指向的线程是“t1、t2线程对象”
		System.out.println(t.getName());//Thread-0 t2线程
	}
}

(2)线程优先级

package javase.jingjie.多线程;
/**
 * 线程优先级高的获取的CPU时间片相对多一些。
 * 优先级:1~10  最低1, 默认5,最高10
 * */
public class DuoXianCheng04 {

	public static void main(String[] args) {
		
		System.out.println(Thread.MAX_PRIORITY);
		System.out.println(Thread.MIN_PRIORITY);
		System.out.println(Thread.NORM_PRIORITY);
		
		//多态,父类型指向子类型,子赋给父
		Thread t1=new Processor03();
		t1.setName("t1线程");
		
		Thread t2=new Processor03();
		t2.setName("t2线程");
		
		//获取默认优先级 5
		System.out.println(t1.getPriority());
		System.out.println(t2.getPriority());
		
		//设置优先级
		t1.setPriority(5);
		t2.setPriority(8);
		
		//启动线程
		t1.start();
		t2.start();
	}

}
class Processor03 extends Thread{
	public void run() {
		for(int i=0;i<50;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}
}

(3)Thread.sleep(毫秒),阻塞当前线程

package javase.jingjie.多线程;
/**
 * 1.Thread.sleep(毫秒)
 * 2.sleep方法是一个静态方法,用类名调用
 * 该方法 的作用:阻塞当前线程,腾出CPU,让给其他线程
 * */
public class DuoXianCheng05 {
	public static void main(String [] args)throws Exception{
		Thread t=new Processor04();
		t.setName("t线程");
		t.start();
		
		//阻塞主线程
		for(int i=0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			//sleep异常可以上抛到main方法,与run方法不同
			//sleep()是一个静态方法,用类名去调用
			Thread.sleep(500);//阻塞主线程0.5秒
		}
		
		//等同于类名. Thread.sleep(),还是主线程,等10秒输出hello World
		t.sleep(10000);//编译用t调用,实际运行调用是Thread
		System.out.println("hello World");
	}
}
class Processor04 extends Thread{
	//Thread中的run方法不抛出异常,所以重写run方法之后,在run方法声明的位置上不能使用throws
	//所以只能用try catch语句块
	public void run() {
		for(int i=0;i<10;i++) {
			//currentThread()是一个静态方法,用类名去调用
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			try {
				//编译异常语句,sleep()是一个静态方法,用类名去调用
				Thread.sleep(1000);//让当前线程阻塞 1秒
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}

(4) 打断线程的睡眠 t.interrupt();

package javase.jingjie.多线程;
/**
 * 某线程正在睡眠,打断她的睡眠
 * */
public class DuoXianCheng06 {

	public static void main(String[] args) throws Exception{
		
		//需求:启动线程,5秒之后打断线程的休眠
		//第二种方法:实现接口方法的创建方式
		Thread t=new Thread(new Processor05());
		t.setName("t线程");
		//启动run方法
		t.start();
		
		//主线程5秒之后,开始打断t线程的休眠
		//此异常可以上抛,不在run()方法中
		Thread.sleep(5000);
		
		//打断t线程休眠
		t.interrupt();
	}

}
class Processor05 implements Runnable{
	public void run() {
		//run中的静态方法sleep()异常只能用try catch语句块处理
		try {
			//休眠
			Thread.sleep(1000000000L);
			
			//下面的代码不会输出,因为上面的语句是异常语句
			System.out.println("Hello World");
			
		}catch(InterruptedException e) {
			//打印异常语句,可以不写该语句
			e.printStackTrace();/*java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at javase.jingjie.多线程.Processor05.run(DuoXianCheng06.java:30)
	at java.base/java.lang.Thread.run(Thread.java:835)*/
		}
		
		for(int i=0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}
}

(5) 线程启动5秒之后终止,终止代码:p.run=false;

package javase.jingjie.多线程;
/**
 * 需求:线程启动5秒之后终止
 * */
public class DuoXianCheng07 {

	public static void main(String[] args) throws Exception{
		
		Processor06 p=new Processor06();
		Thread t=new Thread(p);
		t.setName("t");
		t.start();
		
		//5秒之后终止
		Thread.sleep(5000);
		
		//终止代码
		p.run=false;
	}

}
class Processor06 implements Runnable{
	
	boolean run =true;
	
	public void run() {
		for(int i=0;i<10;i++) {
			if(run) {
				try {
				Thread.sleep(1000);
			}catch(Exception e) {}
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			}else {
				return;
			}
			
		}
	}
}

(6) 同一优先级线程让位:Thread.yield();

package javase.jingjie.多线程;
/**
 * Thread.yield();
 * 1.该方法是一个静态方法。
 * 2.作用:给同一个优先级的线程让位,但是让位时间不固定。
 * 3.和sleep方法相同,就是yield时间不固定
 * */
public class DuoXianCheng08 {

	public static void main(String[] args) {
		Thread t=new Processor07();
		t.setName("t");
		t.start();
		
		//主线程中
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}

}
class Processor07 extends Thread{
	
	public void run() {
		for(int i=0;i<100;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			if(i%20==0) {
				Thread.yield();
			}
		}
	}
}

(7)线程的合并: t.join()

package javase.jingjie.多线程;
/**
 * 线程的合并
 * */
public class DuoXianCheng09 {

	public static void main(String[] args) throws Exception{

		Thread t=new Thread(new Processor08());
		t.setName("t线程");
		t.start();
		
		//合并线程,t在哪个线程就合并哪个线程,成为单线程的程序
		t.join();//t和主线程合并,有异常向上抛出
		
		//主线程
		for(int i=0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}

}
class Processor08 implements Runnable{
	public void run() {
		for(int i=0;i<5;i++) {
			try {
				Thread.sleep(1000);
			}catch(Exception e) {}
			System.out.println(Thread.currentThread().getName()+"-->"+i);
		}
	}
}

3. 线程锁机制:synchronized

锁机制(线程同步机制):synchronized关键词

同步条件:(1)线程必须有共享对象(成员方法才有对象 );(2)在共享对象前提下,还要有共享数据;

  • 1.当2个线程前面有synchronized,且2个线程共享当前对象/锁(this)时,谁先线程启动,并执行run,则第二个线程等待第一个归还锁(共享对象)后,开始启动执行共享对象;
  • 2.同步机制总结就是:谁先synchronized谁先执行,第二个等待归还锁(当前共享对象this)后,接着执行;
  • 3.线程不共享对象,即使2个都有synchronized,也不同步,即各自执行 ;
  • 4.假如有一个没有synchronized,则不需要等待

(1) 成员方法的锁机制

package javase.jingjie.多线程;
public class DuoXianCheng10 {

	public static void main(String[] args) throws Exception{
		
		//mc作为共享对象,给几个线程(t1,t2)共享
		MyClass mc=new MyClass();
		Processor09 p=new Processor09(mc);
		
		//p里面放着共享的mc对象
		Thread t1=new Thread(p);
		t1.setName("t1");
		
		Thread t2=new Thread(p);
		t2.setName("t2");
		
		//启动线程
		t1.start();
		//延迟10s后,t2开始启动(保证t1线程先启动,并执行run)
		Thread.sleep(500);
		t2.start();
	}

}
class Processor09 implements Runnable{
	
	MyClass mc;
	
	public Processor09(MyClass mc) {
		this.mc=mc;
	}
	
	public void run() {
		if(Thread.currentThread().getName().equals("t1")) {
			mc.m1();
		}
		if(Thread.currentThread().getName().equals("t2")) {
			mc.m2();
		}
	}
}
class MyClass{
	
	public synchronized void m1() {
		//休眠
		try {
			Thread.sleep(10000);
		}catch(Exception e) {}
		
		System.out.println("m1...");
	}
	
	/*m2方法的执行不需要等m1结束,因为m2方法上没有synchronized
	public void m2() {
		System.out.println("m2没有synchronized,不用等t1");
	}
	*/
	
	//m2方法会等m1方法结束,t1、t2共享同一个mc,并且m1、m2方法上都有synchronized
	public synchronized void m2() {
		System.out.println("m2有synchronized,等t1");
	}
}

(2) 类锁机制:静态方法的锁机制

package javase.jingjie.多线程;
/**
 * 类锁:类只有一个,所以锁是类级别的,只有一个
 * */
public class DuoXianCheng11 {

	public static void main(String[] args) throws Exception{
		
		Thread t1=new Thread(new Processor10());
		Thread t2=new Thread(new Processor10());
		
		t1.setName("t1");
		t2.setName("t2");
		
		//启动,执行run方法
		t1.start();
		//延迟,保证t1先执行
		Thread.sleep(1000);//代表在主线程中延迟1s,之后执行t2
		t2.start();
	}

}
class Processor10 implements Runnable{
	public void run() {
		if("t1".equals(Thread.currentThread().getName())) {
			MyClass01.m1();
		}
		
		if("t2".equals(Thread.currentThread().getName())) {
			MyClass01.m2();
		}
	}
}
class MyClass01{
	//synchronized添加到静态方法上,线程执行此方法的时候会找类锁
	public synchronized static void m1() {
		try {Thread.sleep(10000);}catch(Exception e) {}
		
		System.out.println("m1....");
	}
	
	//不会等m1结束,因为该方法没有被synchronized修饰
	/*
	public static void m2() {
		System.out.println("m2....");
	}*/
	
	//m2方法等m1结束后才能执行,该方法有synchronized,
	//线程执行该代码需要“类锁”,而类锁只有一个
	public synchronized static void m2() {
		System.out.println("m2....");
	}
}

(3)类锁机制:与静态锁有关,与对象锁无关,可以不共享对象

package javase.jingjie.多线程;
/**
 * 类锁:类只有一个,所以锁是类级别的,只有一个.
 * 
 * 注意:带有synchronized static即使不共享对象,也需要等,这是静态,与类锁有关,和对象锁无关
 * */
public class DuoXianCheng12 {

	public static void main(String[] args) throws Exception{
		
		//带有synchronized static即使不共享对象,也需要等,这是静态,与类锁有关
		MyClass02 mc1=new MyClass02();
		MyClass02 mc2=new MyClass02();
		
		Thread t1=new Thread(new Processor11(mc1));
		Thread t2=new Thread(new Processor11(mc2));
		
		t1.setName("t1");
		t2.setName("t2");
		
		//启动,执行run方法
		t1.start();
		//延迟,保证t1先执行
		Thread.sleep(1000);//代表在主线程中延迟1s,之后执行t2
		t2.start();
	}

}
class Processor11 implements Runnable{
	
	MyClass02 mc;
	
	public Processor11 (MyClass02 mc) {
		this.mc=mc;
	}
	
	public void run() {
		if("t1".equals(Thread.currentThread().getName())) {
			mc.m1();//mc底层用的还是类锁,和对象锁无关
		}
		
		if("t2".equals(Thread.currentThread().getName())) {
			mc.m2();
		}
	}
}
class MyClass02{
	
	//synchronized添加到静态方法(static )上,线程执行此方法的时候会找类锁
	public synchronized static void m1() {
		try {Thread.sleep(10000);}catch(Exception e) {}
		
		System.out.println("m1....");
	}
	
	//不会等m1结束,因为该方法没有被synchronized修饰
	/*
	public static void m2() {
		System.out.println("m2....");
	}*/
	
	//m2方法等m1结束后才能执行,该方法有synchronized,
	//线程执行该代码需要“类锁”(static ),而类锁只有一个
	public synchronized static void m2() {
		System.out.println("m2....");
	}
}

(4) 死锁

package javase.jingjie.多线程;
/**
 * 死锁
 * */
public class DuoXianCheng13 {

	public static void main(String[] args) {
		
		Object o1=new Object();
		Object o2=new Object();
		
		Thread t1=new Thread(new T1(o1,o2));
		Thread t2=new Thread(new T2(o1,o2));
		
		t1.start();
		t2.start();
	}

}
class T1 implements Runnable{
	Object o1;
	Object o2;
	
	T1(Object o1,Object o2){
		this.o1=o1;
		this.o2=o2;
	}
	
	public void run() {
		synchronized(o1) {
			try {Thread.sleep(1000);}catch(Exception e) {}
			synchronized (o2) {
				
			}
		}
	}
}
class T2 implements Runnable{
	Object o1;
	Object o2;
	
	T2(Object o1,Object o2){
		this.o1=o1;
		this.o2=o2;
	}
	
	public void run() {
		synchronized(o2) {
			try {Thread.sleep(1000);}catch(Exception e) {}
			synchronized (o1) {
				
			}
		}
	}
}

4. 守护线程和定时器

(1) 守护线程:t1.setDaemon(true)

package javase.jingjie.多线程;
/**
 * 守护线程:
 * 其他所有的用户线程结束,则守护线程退出!
 * 守护线程一般是无限执行的
 * */
public class DuoXianCheng14 {

	public static void main(String[] args) throws Exception{
		
		Thread t1=new Processor13();
		t1.setName("t1");
		
		//将t1这个用户线程修改成守护线程
		t1.setDaemon(true);
		t1.start();
		
		//主线程
		for(int i=0;i<10;i++) {
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			Thread.sleep(1000);
		}
	}
}
class Processor13 extends Thread{
	public void run() {
		int i=0;
		
		//无线循环,但变成守护线程后,其他用户线程结束,则守护线程可以退出
		while(true) {
			i++;
			System.out.println(Thread.currentThread().getName()+"-->"+i);
			try {
				Thread.sleep(500);
			}catch(Exception e) {}
		}
	}
}

(2) 定时器的应用

package javase.jingjie.多线程;
/**
 * 关于定时器的应用:
 * 作用:每隔一段固定的时间执行一段代码
 * */
import java.util.*;
import java.text.*;
public class DuoXianCheng15 {

	public static void main(String[] args) throws Exception{
		// 1.创建定时器
		Timer t=new Timer();
		
		//2.指定定时任务
		t.schedule(new LogTimerTask(), //任务
				new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss:SSS").parse("2019-10-29,18:10:23:234"),//时间,parse字符串转日期
				10*1000);//间隔时间

	}
}
//指定任务
class LogTimerTask extends TimerTask{
	public void run() {
		//format-->将日期转化成字符串
		System.out.println(new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss:SSS").format(new Date()));
	}
}
发布了71 篇原创文章 · 获赞 10 · 访问量 3423

猜你喜欢

转载自blog.csdn.net/JH39456194/article/details/104065106