1-线程的基本使用
0
Word Count: 2k(words)
Read Count: 8(minutes)
一、简单定义
什么是进程

2.线程与进程
线程由进程创建。
3.并发与并行

二、线程的使用
使用 继承 thread 类。重写 run 方法
实现 Runnable 接口,重写 run 方法,并将其对象传入 thread 的构造器中创建 thread 对象
1.Extend thread
1 2 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 类进行代理。
1 2 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 方法退出的方式停止进程,即通知方式。
1 2 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.用户线程和守护线程
1 2 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.线程死锁
多个线程都占用了对方的锁资源,但不肯相让,导致了死锁。
一个案例
1 2 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 方法。–>看源码分析
1 2 3 4 5 6 7 8
| public synchronized void start() { start0(); }
private native void start0();
|