Java当中的多线程

线程 Thread

程序:保存在物理介质(磁盘、光盘、软盘)中的代码片段

进程:一旦程序运行起来 就变成操作系统当中的一个进程
进程 = 进行当中的程序

线程:程序当中一条独立的执行线索

为什么要使用多线程:
并不是单纯的为了效率 而是为了让程序
学会同时处理多个需求
让程序学会同一时间做多件事

宏观并行 而 微观串行

线程的五大状态(七大):

  新生		就绪		运行		消亡
  Born		Runnable	Running		Dead

			阻塞
			Blocking

如何实现多线程的程序:

1.extends Thread
		@Override
		public void run(){
			..;
		}
	2.implements Runnable
		@Override
		public void run(){
			..;
		}

	3.implements Callable<T>
		@Override
		public T call()throws Exception{
			..;
		}
		*: run()被定义为void 不能返回数据
		*: run()没有任何throws

如何控制线程:
0.setPriority(int) : 设置线程优先级别
可选范围 1-10 默认为 5
*:优先级高的线程抢到时间片的概率高

1.static sleep(long) : 让当前线程休眠指定的毫秒数
2.static yield() : 让当前线程放弃已经持有的时间片 直接返回就绪
3.join() : 当前线程邀请另一个线程优先执行
	在被邀请的线程执行结束之前 当前线程不再继续执行

*: 线程章节所有的静态方法 不要关注谁调用方法
	而要关注调用出现在哪 出现在谁的线程体 
	就是操作哪个线程

*: 线程章节所有涉及主动进入阻塞的方法 
	都需要进行异常处理

线程类其它常用方法:

setName() + getName()  : 设置和得到线程的名字
static activeCount() : 得到程序当中所有活跃线程的总数
	活跃 = 就绪 + 运行 + 阻塞
static currentThread() : 得到正在运行的当前线程
setDaemon(true) : 设置线程成为守护线程
	守护线程 = 守护线程是为其他线程提供服务的线程
		  当程序当中只有守护线程的时候 守护线程会自行结束
	*: gc就是一个系统级别的守护线程
interrupt() : 中断打断线程的阻塞状态

线程类方法总结:

run()
	start()
	setPriority()
	sleep()
	yield()
	join()
	setName()
	getName()
	activeCount()
	currentThread()
	setDaemon()
	interrupt()

多线程共享数据导致的并发错误:

扫描二维码关注公众号,回复: 6681006 查看本文章

根本原因:多线程共享同一个数据
直接原因:线程体当中连续的未必能够连续执行
导火索:时间片突然耗尽

多个线程共享同一个对象的时候 由于线程体当中连续的多行操作
	未必能够连续执行 很可能操作了一部分之后
	由于时间片突然耗尽 导致另一个线程抢到时间片
	而直接取走了操作并不完整的数据 (错误的数据)

					- 并发错误

多个线程共享的数据:临界资源

如何解决并发错误:

1st : synchronized 同步

	Java当中每个对象都有一个锁标记
	锁标记 = 锁旗标 = 互斥锁 = 互斥锁标记 = 监视器 = Monitor

	 a> 修饰代码块 : 
		synchronized(临界资源){
			需要连续执行的操作1;
			需要连续执行的操作2;
		}

	 b> 修饰整个方法:
		public synchronized void add(Object obj){...}
		等价于从方法的第一行到方法的最后一行统统加锁
		对调用方法的当前对象加锁

		#: Vector Hashtable StringBuffer
			它们之所以是线程安全的
			就是因为底层大量的方法使用了synchronized
		#: synchronized特性不会被子类方法继承 只能覆盖
	

	2nd : java.util.concurrent.locks.ReentrantLock
		java包的工具包的并发包的锁包的 可重入锁
	
			lock() 	 上锁
			unlock() 解锁

互斥锁标记使用过多 或者使用不当
就会造成多个线程相互持有对方想要申请的资源 不释放的情况下
又去申请对方已经持有的资源
从而双双进入对方已经持有资源的锁池当中
产生永久的阻塞

				- 死锁 DeadLock
1> 中美科学家联合国饿死事件

2> 泉城路奔宝事件

3> AABB事件

```

如何解决死锁:

一块空间:对象的等待池
三个方法:
wait() : 让当前线程放弃已经持有的锁标记
并且进入调用方法的那个对象的等待池当中

notify() : 让当前线程从 调用方法的那个对象的
	等待池当中随即唤醒一个线程

notifyAll() : 让当前线程从 调用方法的那个对象的
	等待池当中唤醒全部线程

*:它们都是Object类的方法 并不是 Thread类的方法
*:想要调用这三个方法 必须先持有对象的锁标记
所以它们必然出现在synchronized当中

Java当中线程池的实现:
假如一个线程的完整执行时间为 T
则 T = t1 + t2 + t3
t1 : 创建一个线程所消耗的时间
t2 : 执行核心逻辑的时间
t3 : 销毁一个线程所消耗的时间

假如run()当中代码逻辑非常简单
则t2所占T的比例就会很小 此时喧宾夺主 主次不分
public class TestActiveCount{
	public static void main(String[] args){
		int lucky = (int)(Math.random()*10)+1;//1-10
		for(int i = 0;i<lucky;i++){
			EtoakThread et = new EtoakThread();
			et.start();
		}

		while(true){
			System.out.println(Thread.activeCount());
		}
	}
}
class EtoakThread extends Thread{
	@Override
	public void run(){
		for(int i = 0;i<6666;i++){
			System.out.println("ÕýÔÚÍê³É·þÎñ");
		}
	}
}
public class TestConcurrentError{
	public static void main(String[] args){
		Student stu = new Student("张曼玉","女士");
		PrintThread pt = new PrintThread(stu);
		ChangeThread ct = new ChangeThread(stu);
		pt.start();
		ct.start();
	}
}
class Student{
	String name;
	String gender;
	public Student(String name,String gender){
		this.name = name;
		this.gender = gender;
	}
	@Override
	public String toString(){
		return name + " : " + gender;
	}
}
class PrintThread extends Thread{
	Student stu;
	public PrintThread(Student stu){
		this.stu = stu;
	}
	@Override
	public void run(){
		while(true){
			synchronized(stu){
				System.out.println(stu);
			}
		}
	}
}
class ChangeThread extends Thread{
	Student stu;
	public ChangeThread(Student stu){
		this.stu = stu;
	}
	@Override
	public void run(){
		boolean isOkay = true;
		while(true){
			synchronized(stu){
				if(isOkay){
					stu.name = "梁朝伟";//梁朝伟 女士
					stu.gender = "先生";//梁朝伟 先生
				}else{
					stu.name = "张曼玉";//张曼玉 先生
					stu.gender = "女士";//张曼玉 女士
				}
				isOkay = !isOkay;
			}
		}
	}
}

public class TestCurrentThread{
	public static void main(String[] args){
		EtoakThread et = new EtoakThread();
		et.start();
		et.setPriority(10);

		Thread main = Thread.currentThread();
		main.setPriority(10);

		while(true){
			System.out.println("我为人人");
		}
	}
}
class EtoakThread extends Thread{
	@Override
	public void run(){
		while(true){
			System.out.println("人人为我");
		}
	}
}
public class TestDeadLock{
	public static void main(String[] args){
		QCRoad r = new QCRoad();
		QCRoad.Benz s900 = r.new Benz();
		QCRoad.Bmw x9 = r.new Bmw();
		s900.start();
		x9.start();
	}
}
class QCRoad{
	Object east = new Object();
	Object west = new Object();

	class Benz extends Thread{
		@Override
		public void run(){
			System.out.println("张总驾驶奔驰驶出家门去上学");
			synchronized(east){
				System.out.println("张总已经占领了泉城路东侧");
				try{sleep(100);}catch(Exception e){e.printStackTrace();}
				try{east.wait();}catch(Exception e){e.printStackTrace();}
				synchronized(west){
					System.out.println("张总又占领了泉城路西侧");
				}
			}
			System.out.println("张总顺利的通过了泉城路");
		}
	}
	class Bmw extends Thread{
		@Override
		public void run(){
			System.out.println("王总驾驶宝马驶出家门去上学");
			synchronized(west){
				System.out.println("王总已经占领了泉城路西侧");
				try{sleep(100);}catch(Exception e){e.printStackTrace();}
				synchronized(east){
					System.out.println("王总又占领了泉城路东侧");
					east.notify();
				}
			}
			System.out.println("王总顺利的通过了泉城路");
		}
	}
}
public class TestSetPriority{
	public static void main(String[] args){
		ThreadOne t1 = new ThreadOne();
		t1.setPriority(1);
		t1.start();
		ThreadTwo t2 = new ThreadTwo();
		t2.setPriority(10);
		t2.start();
	}
}

class ThreadOne extends Thread{//敬明
	@Override
	public void run(){
		while(true){
			System.out.println("小明去打篮球吗 不!我要写小说");//140cm
		}
	}
}
class ThreadTwo extends Thread{
	@Override
	public void run(){
		while(true){
			System.out.println("小明去图书馆看书吗 不!我要打篮球");//226cm
		}
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_39381833/article/details/90740080