共计 3487 个字符,预计需要花费 9 分钟才能阅读完成。
一、线程根底内容
1、程序、过程与线程
1、程序:Program, 是一个指令的汇合
2、过程:Process,(正在执行中的程序) 是一个动态的概念过程是程序的一次动态执行过程,占用特定地的地址空间
每个过程都是独立的,由 3 局部组成 cpu,data,code
毛病:内存的节约,cpu 的累赘3、线程: 是过程中一个“繁多的间断管制流程”/ 执行门路
线程又被成为轻量级过程
Threads run at the same time,independently of one another
一个过程可领有多个并行的线程
一个过程中的线程共享雷同的内存单元 / 内存地址空间 -> 能够拜访雷同的变量和对象,而且他们从同一堆中调配对象 -> 通信、数据交换、同步操作
因为线程间的通信是在同一地址空间上进行的,所以不须要额定的通信机制,这就使得通信更简便而且信息的传递速度也更快
2、线程的创立和启动
2.1、第一种形式
继承 Thread 类,从新 run 办法,调 start(启动线程),每次运行雷同的代码,进去的后果可能不一样,起因在于多线程谁先抢占资源无奈进行认为管制
package com.msbline.threadPkg;
public class ThreadDemo extends Thread{
@Override
public void run() {for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName() +"---"+ i);
}
}
public static void main(String[] args) {ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName() +"==="+ i);
}
}
}
2.2、第二种形式
实现 Runnable 接口,重写 run 办法,创立 Thread 对象,将刚刚创立好的 Runnable 的子类实现作为 Thread 的结构参数,通过 Trhead.start()进行启动
package com.msbline.threadPkg;
public class ThreadDemo02 implements Runnable{
@Override
public void run() {for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName() +"---"+ i);
}
}
public static void main(String[] args) {ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
for (int i = 0; i < 10; i++){System.out.println(Thread.currentThread().getName() +"==="+ i);
}
}
}
两种形式哪种应用更多
3、线程的生命周期
4、线程的代理设计模式
5、线程操作的相干办法
1、sleep 办法是属于 Thread 类中的,sleep 过程中线程不会开释锁,只会阻塞线程,让出 cpu 给其余线程,然而他的监控状态仍然放弃着,当指定的工夫到了又会主动复原运行状态,可中断,sleep 给其余线程运行机会时不思考线程的优先级,因而会给低优先级的线程以运行的机会
2、yield 和 sleep 一样都是 Thread 类的办法,都是暂停以后正在执行的线程对象,不会开释资源锁,和 sleep 不同的是 yield 办法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只须要期待从新获取 CPU 执行工夫,所以执行 yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 办法只能使同优先级或更高优先级的线程有执行的机会
3、join,期待调用 join 办法的线程完结之后,程序再继续执行,个别用于期待异步线程执行完后果之后能力持续运行的场景。例如:主线程创立并启动了子线程,如果子线程中药进行大量耗时运算计算某个数据值,而主线程要获得这个数据值能力运行,这时就要用到 join 办法了
4、wait 办法是属于 Object 类中的,wait 过程中线程会开释对象锁,只有当其余线程调用 notify 能力唤醒此线程。wait 应用时必须先获取对象锁,即必须在 synchronized 润饰的代码块中应用,那么相应的 notify 办法同样必须在 synchronized 润饰的代码块中应用,如果没有在 synchronized 润饰的代码块中应用时运行时会抛出 IllegalMonitorStateException 的异样
二、线程同步
1、线程同步的必要性
多个线程拜访同一个共享数据的时候,会呈现数据安全问题,比方买票,两个线程同时对一张票进行操作,可能会导致重票的问题
2、线程同步的实现
2.1、同步代码块
synchronized(共享资源,共享对象,须要是 Object 的子类){具体执行的代码块}
public class TicketRunnable2 implements Runnable{
private int ticket = 5;
@Override
public void run() {for(int i = 0; i<100; i++){
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}
synchronized (this){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"正在发售第"+(ticket--)+"票");
}
}
}
}
public static void main(String[] args) {TicketRunnable2 ticketRunnable = new TicketRunnable2();
Thread t1 = new Thread(ticketRunnable,"A");
Thread t2 = new Thread(ticketRunnable,"B");
Thread t3 = new Thread(ticketRunnable,"C");
Thread t4 = new Thread(ticketRunnable,"D");
t1.start();
t2.start();
t3.start();
t4.start();}
}
2.2、同步办法
public class TicketRunnable3 implements Runnable{
private int ticket = 5;
@Override
public void run() {for(int i = 0; i<100; i++){
try {Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();
}
this.sale();}
}
/**
* 应用同步办法解决
*/
public synchronized void sale(){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"正在发售第"+(ticket--)+"票");
}
}
public static void main(String[] args) {TicketRunnable3 ticketRunnable = new TicketRunnable3();
Thread t1 = new Thread(ticketRunnable,"A");
Thread t2 = new Thread(ticketRunnable,"B");
Thread t3 = new Thread(ticketRunnable,"C");
Thread t4 = new Thread(ticketRunnable,"D");
t1.start();
t2.start();
t3.start();
t4.start();}
}
3、死锁
4、线程同步小结
三、线程间通信
1、线程间通信的必要性
一般来说,每个线程本人实现本人的工作就能够了,但有时候,线程的解决会依赖另一个线程的数据,所以就须要线程间通信,来达到同步信息的成果。
2、线程间通信的实现
参考:https://blog.csdn.net/jisuanji12306/article/details/86363390