1-线程的基本使用
    
  
      
      
        
    
	
	  
	
        
        
        
	
	    
	    
			0
		
	
        
        
	
		Word Count: 2k(words)
	
	
		Read Count: 8(minutes)
	
       
     
    
      
        
一、简单定义
- 什么是进程  
 
2.线程与进程
线程由进程创建。
3.并发与并行

二、线程的使用
- 使用 继承 thread 类。重写 run 方法 
- 实现 Runnable 接口,重写 run 方法,并将其对象传入 thread 的构造器中创建 thread 对象 
1.Extend thread
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | public class threadsEXtend {public static void main(String[] args) throws InterruptedException {
 Dog dog = new Dog();
 dog.start();
 for (int i = 0; i < 20; i++) {
 System.out.println("这是主线程"+Thread.currentThread().getName());
 Thread.sleep(1000);
 }
 }
 }
 class Dog extends  Thread{
 @Override
 public void run() {
 int count=1;
 while (true){
 System.out.println("小狗汪汪"+"线程名"+currentThread().getClass()+count++);
 try {
 sleep(1000);
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 if (count==30){
 break;
 }
 }
 }
 }
 
 | 
2.implement Runnable 解决该类已经有 基继承的类
Thread 中具有代理模式的设计模式。
具有 一个 runnable 类型 的 Target
然后还有一个 构造器,可以接受一个 实现了 runnale 接口的类。
 因为 runnable 接口没有 start 方法,创建 线程需要调用 start 方法,所以需要 thread 类进行代理。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | package com.threadUser;
 public class ThreadProxy {
 public static void main(String[] args) {
 Cat cat = new Cat();
 Thread thread = new Thread(cat);
 thread.run();
 }
 }
 class Cat implements Runnable{
 @Override
 public void run() {
 int count=1;
 for (int i = 0; i < 30; i++) {
 System.out.println("线程名" +"第"+count++ +"此");
 
 }
 }
 }
 
 
 | 
3. extend 和 implement runnable  的区别
- Runnable 更适合 多个线程共享一个资源的情况,并且避免了单继承的限制  
 
4.通知线程退出
- 线程完成任务后,会自动退出
- 可以使用==控制变量==来控制 run 方法退出的方式停止进程,即通知方式。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | 安丽package com.threadUser;
 
 public class ThreadExit_ {
 public static void main(String[] args) throws InterruptedException {
 exitTest exitTest = new exitTest();
 exitTest.start();
 System.out.println("等待五秒后手动关闭");
 Thread.sleep(5*1000);
 exitTest.setLoop(false);
 }
 }
 class exitTest extends Thread{
 private boolean loop=true;
 int count=1;
 @Override
 public void run() {
 while (loop){
 System.out.println("正在运行"+count++);
 try {
 
 sleep(500);
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 }
 }
 public void setLoop(boolean loop){
 this.loop=loop;
 }
 }
 
 | 
5.常用方法
- 1.setName //设置线程名字
- 2.getName //返回线程名称
- 3.start 启动该线程,jvm 底层调用该进程的 start0 方法
- 4.run //直接调用线程对象的 run 方法
- 5-setPriority //更改线程的优先级
- 6-getPriority //获取线程的优先级
- 7-sleep //让线程指定休眠  xxx 毫秒 (暂停执行)
- 8- interrupt //中断==线程的休眠==
- 9- yield :线程的礼让,让出 CPU ,让其他线程先执行,但礼让的时间不一定,所以礼让也==不一定成功==。
- 是否礼让由系统资源决定,操作系统内核负责处理,这一块 java 无法控制
 
- 10- join:线程的插队,插队的线程一旦插队成功,则肯定==先执行完插入的线程的所有任务==。
6.用户线程和守护线程
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | 线程对象.setDaemon(true) --->守护进程。setDaemon要在 start 之前设置。
 案例
 
 
 package com.threadUser;
 
 public class SetDamon_ {
 public static void main(String[] args) {
 damon_ damon_ = new damon_();
 damon_.setDaemon(true);
 damon_.start();
 for (int i = 0; i < 5; i++) {
 System.out.println(i);
 if (i==4){
 System.out.println("不,你是守护进程,你要和我一起走。");
 }
 }
 }
 }
 class damon_ extends Thread{
 @Override
 public void run() {
 while (true){
 System.out.println("我还要继续!!");
 }
 }
 }
 
 
 | 

注意点
- 当处于 Runnable状态时,并不是一定在进行,而是由 操作系统的线程调度器负责 调配运行。—>由操作系统内核决定。(内核态)
- 官方文档为 6 种状态,但一般 又将 runnable 细分为两种转态,即有7 钟转态
可以使用 jconsole 工具 查看线程


三、生命周期
1.生命周期

2.线程同步机制
1)线程同步机制 Synchronizd
一个敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。

2.synchronize 使用
四、锁

这里的同步方法是否是 静态的 非常重要。—Synchronized
如果是 this  ,则是 当前对象,如果不同对象,不会造成堵塞。
如果是==静态(stastic)==, 则是  加在该类的 Class 中(类加载的知识) ,该==类的不同对象==,会造成==堵塞==。  
1.注意事项和细节:
2.线程死锁
多个线程都占用了对方的锁资源,但不肯相让,导致了死锁。
一个案例
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 
 | package com.hspedu.syn;
 
 
 
 
 public class DeadLock_ {
 public static void main(String[] args) {
 
 DeadLockDemo A = new DeadLockDemo(true);
 A.setName("A 线程");
 DeadLockDemo B = new DeadLockDemo(false);
 B.setName("B 线程");
 A.start();
 B.start();
 }
 }
 
 韩顺平循序渐进学 Java 零基础
 第 810页
 class DeadLockDemo extends Thread {
 static Object o1 = new Object();
 static Object o2 = new Object();
 boolean flag;
 public DeadLockDemo(boolean flag) {
 this.flag = flag;
 }
 @Override
 public void run() {
 
 
 
 
 
 if (flag) {
 synchronized (o1) {
 System.out.println(Thread.currentThread().getName() + " 进入 1");
 synchronized (o2) {
 System.out.println(Thread.currentThread().getName() + " 进入 2");
 }
 }
 } else {
 synchronized (o2) {
 System.out.println(Thread.currentThread().getName() + " 进入 3");
 synchronized (o1) {
 System.out.println(Thread.currentThread().getName() + " 进入 4");
 }
 }
 }
 }
 }
 
 | 
3.释放锁
释放锁的问题。

下列操作不会释放锁
- sleep、yield
 太困了,但还在厕所里面。
- 线程被挂起.suspend()。
  

六、一些疑问
- 为什么调用的是 start 方法,而不是直接调用 run 方法
A: 直接调用 run 方法,那就是相当于普通的方法调用,只会在主栈中调用,不会创建新线程。而调用 start 方法可以创建新 线程并 会自动调用 run 方法。–>看源码分析
| 12
 3
 4
 5
 6
 7
 8
 
 | public synchronized void start() {
 start0();
 }
 
 
 private native void start0();
 
 
 |