Lock-线程组-线程池-线程状态的转换图
2017-12-08 16:42
246 查看
一.Lock(接口)
1.使用同步机制的方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况,jdk5以后java提供了一个更具体的锁对象
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
Lock是一个接口,所以它在使用时用
ReentrantLock子实现类
2.加锁和释放锁的方法:
public void lock()获取锁
public void unlock()试图释放此锁
try{
锁对象.lock()
..........
}finally{
锁对象.unlock()
//释放资源
}
package lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTickets implements Runnable{
private static int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
// 模拟电影院售票,假设一直有票
while (true){
//加锁
try{
lock.lock();
if(tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets--+"张票");
}
//释放锁
}finally{
lock.unlock();
}
}
}
}
优点:解决多线程的安全问题
缺点:1)同步,执行效率低(每个线程在抢占到CPU的执行权后,会将门关闭,其他线程不能进来)
2)容易出现死锁:两个或者两个以上的线程出现了互相等待的情况,容易死锁
4.线程间的通信:生产者消费者模式(多个线程对同一资源进行操作)
例子: 1)资源对象:Student类
提供一些成员变量:姓名 和年龄
2)生产者线程:SetThread类: 生产一些学生数据(设置学生数据)
3)消费者线程:GetThread类: 输出学生数据
4)测试类:StudentDemo类,实现多线程环境
对于生产者来说,产生数据,如果处于等待(wait)状态就说名有数据,通知消费者有线程,赶紧输出数据
对于消费者线程,输出数据,如果没有数据,应该通知生产者产生数据。
以上是一个多线程环境,会出现线程不安全:
1)同一数据打印一片(CPU的一点点时间片足够执行很多此)
2)年龄和姓名不符合(线程的随机性导致的)
使用等待唤醒机制可以解决问题1);使用同步机制可以解决问题2)
package waitnotify;
public class Student {
String name;
int age;
//声明一个变量
boolean flag;//默认没有数据,如果是true,则说明有数据
}
以上例子的成员变量不是私有化,一般成员变量私有化,可以对上面的进行改进
package lastwaitnotify;
public class Student {
private String name;
private int age;
//声明一个变量
private boolean flag; //默认没有数据,如果是true,则说明有数据
//set(String name,int age)方法,产生数据
//同步机制可以解决数据不一致
public synchronized void set(String name,int age){
//等待唤醒机制
//判断有没有数据
if(this.flag){ //对于生产者来说,没有数据,则处于等待状态,
//处于等待状态
try {
this.wait();//阻塞方式,立即释放锁 notify
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//设置学生数据
this.name = name;
this.age = age;
//修改标记
this.flag = true;//有数据
//通知gt:消费者线程来消费
this.notify();//唤醒等待状态
}
//get()输出数据
public synchronized void get(){
if(!this.flag){
try {
this.wait() ;//调用的时候,会立即释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//输出语句
System.out.println(this.name+"---"+this.age);
//修改标记
this.flag = false ;//消费者线程
//通知对方(st线程),消费者线程没有数据类,赶紧来消费
this.notify() ;//唤醒t1线程....
}
}
二.线程组(ThreadGroup)
表示一个线程的集合
1.public final ThreadGroup getThreadGroup()返回该线程的线程组
2.public ThreadGroup(String name)设置线程组名称
3.public Thread(ThreadGroup,Runnable target,String name)给每一个子线程设置线程组名称
package threadgroup;
public class ThreadGroupDemo {
public static void main(String[] args) {
//线程组:一个线程的集合
method1();
method2();
}
//给每一个子线程设置线程名称
private static void method2() {
//public ThreadGroup(String name)构造一个新线程组
ThreadGroup tg = new ThreadGroup("这是一个新的线程组") ;
//创建资源对象
MyRunnable t1 = new MyRunnable();
//创建线程类对象,并且将线程组对象作为参数进行传递,就使用Thread类的构造方法
//public Thread(ThreadGroup group,Runnable target ,String name){}
Thread th1 = new Thread(tg, t1, "线程1") ;
Thread th2 = new Thread(tg, t1, "线程2") ;
//public final ThreadGroup getThreadGroup()返回该线程的线程组
ThreadGroup tg1 = th1.getThreadGroup() ;
ThreadGroup tg2 = th2.getThreadGroup() ;
System.out.println(tg1.getName());
System.out.println(tg2.getName());
tg.setDaemon(true) ;//将线程组中的所有的线程都设置为守护线程(后台线程)
}
private static void method1() {
// 获取多个线程所在的线程组名称
//创建资源对象
MyRunnable tg = new MyRunnable();
//创建线程类对象
Thread t1 = new Thread(tg);
Thread t2 = new Thread(tg);
//获取t1和t2所在的线程名称
//获取线程组对象
//public final ThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
String name1 = tg1.getName();
String name2 = tg2.getName();
//子线程默认的线程组名称:main线程
System.out.println(name1);//main
System.out.println(name2);//main
//所有的线程它的默认线程组名称就是main
System.out.println(Thread.currentThread().getThreadGroup().getName());
}
}
线程池的好处:节约成本,很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用!
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
1)public static ExecutorService
newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。
ExecutorsService :接口中的方法
2)Future<?>
submit(Runnable task)
<T> Future<T> submit(Callable<T> task)package threadpool;
public class MyRunnable implements Runnable {
@Override
public void run() {
while(true){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
创建线程池对象 实现callable接口
package callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 多线程程序的实现方式3:(实际开发中很少用到!)
* public static ExecutorService newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnabl e对象或者Callable对象代表的线程。它提供了如下方法
ExecutorsService :接口中的方法
<T> Future<T> submit(Callable<T> task)
* @author Apple
*/
public class CallableDemo {
public static void main(String[] args) {
// 创建线程池对象
ExecutorService threadpool = Executors.newFixedThreadPool(2);
//提交Callable任务
threadpool.submit(new MyCallable());
threadpool.submit(new MyCallable());
//结束线程池
threadpool.shutdown();
}
}
格式:new 类名(具体类,抽象类),接口(){
重写/实现方法;
}
匿名内部类的本质:继承了该类或者是实现该接口的子类对象!
public class ThreadDemo {
public static void main(String[] args) {
//继承自Thread类
new Thread(){
@Override
public void run() {
//for循环
for(int x = 0 ; x <100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}.start() ;//启动线程
//Runnable接口的方式
new Thread(new Runnable() {
@Override
public void run() {
//for循环
for(int x = 0 ; x < 100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}).start() ;
}五.定时器Timer
常用的方法:
public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
public void schedule(TimerTask task, long delay, long period)在多少毫秒后,执行任务,并且每个多少毫秒重复执行
public void cancel()终止此计时器,丢弃所有当前已安排的任务
TimeTask是一个抽象类,自定义一个类实现它
练习:在指定的时间内删除当前项目下Demo文件夹中的内容
package timer;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String[] args) throws ParseException {
//创建Timer定时器
Timer t = new Timer();
//定义一个文本日期格式
String dateStr = "2017-12-8 16:50:00";
//解析成Date对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//解析方法
Date date = sdf.parse(dateStr);
//public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
//调用定时器在指定的时间内执行某个任务
t.schedule(new DeleteFolder(), date);
}
}
//删除Demo文件夹
class DeleteFolder extends TimerTask{
@Override
public void run() {
// 封装当前项目下的Demo文件
File srcFolder = new File("demo");
deleteFolder(srcFolder);
}
//递归删除
private void deleteFolder(File srcFolder) {
// 获取当前strFolder下面的所以文件及文件夹
File[] fileArray = srcFolder.listFiles();
//对该对象非空判断
if(fileArray!=null){
//增强for遍历
for(File file : fileArray){
//判断file对象是否是文件夹
if(file.isDirectory()){
//继续回到删除目录的方法
deleteFolder(file);
}else{
//不是目录,是文件直接删除
System.out.println(file.getName()+"---"+file.delete());
}
}
System.out.println(srcFolder.getName()+"---"+srcFolder.delete());
}
}
}
1.使用同步机制的方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况,jdk5以后java提供了一个更具体的锁对象
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
Lock是一个接口,所以它在使用时用
ReentrantLock子实现类
2.加锁和释放锁的方法:
public void lock()获取锁
public void unlock()试图释放此锁
try{
锁对象.lock()
..........
}finally{
锁对象.unlock()
//释放资源
}
package lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTickets implements Runnable{
private static int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
// 模拟电影院售票,假设一直有票
while (true){
//加锁
try{
lock.lock();
if(tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets--+"张票");
}
//释放锁
}finally{
lock.unlock();
}
}
}
}
package lock; public class SellTicketsDemo { public static void main(String[] args) { // 创建SynRunnable对象 SellTickets st = new SellTickets(); //创建线程类对象 Thread t1 = new Thread(st,"窗口1"); Thread t2 = new Thread(st,"窗口2"); Thread t3 = new Thread(st,"窗口3"); //开启线程 t1.start(); t2.start(); t3.start(); } }3.同步机制的优缺点
优点:解决多线程的安全问题
缺点:1)同步,执行效率低(每个线程在抢占到CPU的执行权后,会将门关闭,其他线程不能进来)
2)容易出现死锁:两个或者两个以上的线程出现了互相等待的情况,容易死锁
4.线程间的通信:生产者消费者模式(多个线程对同一资源进行操作)
例子: 1)资源对象:Student类
提供一些成员变量:姓名 和年龄
2)生产者线程:SetThread类: 生产一些学生数据(设置学生数据)
3)消费者线程:GetThread类: 输出学生数据
4)测试类:StudentDemo类,实现多线程环境
对于生产者来说,产生数据,如果处于等待(wait)状态就说名有数据,通知消费者有线程,赶紧输出数据
对于消费者线程,输出数据,如果没有数据,应该通知生产者产生数据。
以上是一个多线程环境,会出现线程不安全:
1)同一数据打印一片(CPU的一点点时间片足够执行很多此)
2)年龄和姓名不符合(线程的随机性导致的)
使用等待唤醒机制可以解决问题1);使用同步机制可以解决问题2)
package waitnotify;
public class Student {
String name;
int age;
//声明一个变量
boolean flag;//默认没有数据,如果是true,则说明有数据
}
package waitnotify; //生产者线程 public class SetThread implements Runnable{ private Student s; public SetThread(Student s){ this.s = s; } private int i = 0; @Override public void run() { while(true){ //同步机制可以解决数据不一致 synchronized(s){ //等待唤醒机制 //判断有没有数据 if(s.flag){ //对于生产者来说,没有数据,则处于等待状态, //处于等待状态 try { s.wait();//阻塞方式 } catch (InterruptedException e) { e.printStackTrace(); } } if(i%2==0){ //设置学生数据 s.name = "韩庚"; s.age = 18; }else{ //设置学生数据 s.name = "张靓颖"; s.age = 16; } i++; //修改标记 s.flag = true;//有数据 //通知gt:消费者线程来消费 s.notify();//唤醒等待状态 } } } }
package waitnotify; public class GetThread implements Runnable{ private Student s; public GetThread(Student s){ this.s = s; } @Override public void run() { //使用同步机制可以解决数据不一致现象 while(true){ synchronized(s){ //使用等待唤醒机制 if(!s.flag){ try { s.wait();//调用的时候会立即释放锁 } catch (InterruptedException e) { e.printStackTrace(); } } //输出语句 System.out.println(s.name+"----"+s.age); //修改标记 s.flag = false;//消费者线程没有可输出的数据 //通知对方st线程,消费者线程没有数据,赶紧产生数据 s.notify(); //唤醒st线程 } } } }
package waitnotify; public class StudentDemo { public static void main(String[] args) { // 创建资源对象 Student s = new Student(); //创建资源对象 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //创建线程类对象 Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //分别启动线程 t1.start(); t2.start(); } }
以上例子的成员变量不是私有化,一般成员变量私有化,可以对上面的进行改进
package lastwaitnotify;
public class Student {
private String name;
private int age;
//声明一个变量
private boolean flag; //默认没有数据,如果是true,则说明有数据
//set(String name,int age)方法,产生数据
//同步机制可以解决数据不一致
public synchronized void set(String name,int age){
//等待唤醒机制
//判断有没有数据
if(this.flag){ //对于生产者来说,没有数据,则处于等待状态,
//处于等待状态
try {
this.wait();//阻塞方式,立即释放锁 notify
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//设置学生数据
this.name = name;
this.age = age;
//修改标记
this.flag = true;//有数据
//通知gt:消费者线程来消费
this.notify();//唤醒等待状态
}
//get()输出数据
public synchronized void get(){
if(!this.flag){
try {
this.wait() ;//调用的时候,会立即释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//输出语句
System.out.println(this.name+"---"+this.age);
//修改标记
this.flag = false ;//消费者线程
//通知对方(st线程),消费者线程没有数据类,赶紧来消费
this.notify() ;//唤醒t1线程....
}
}
package lastwaitnotify; //生产者线程 public class SetThread implements Runnable{ private Student s; public SetThread(Student s){ this.s = s; } private int i = 0; @Override public void run() { while(true){ if(i%2==0){ //设置学生数据 s.set("韩庚", 18); }else{ //设置学生数据 s.set("张靓颖", 16); } i++; } } }
package lastwaitnotify; public class GetThread implements Runnable{ private Student s; public GetThread(Student s){ this.s = s; } @Override public void run() { while(true){ s.get(); } } }
package lastwaitnotify; public class StudentDemo { public static void main(String[] args) { // 创建资源对象 Student s = new Student(); //创建资源对象 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //创建线程类对象 Thread t1 = new Thread(st); Thread t2 = new Thre cbf0 ad(gt); //分别启动线程 t1.start(); t2.start(); } }
二.线程组(ThreadGroup)
表示一个线程的集合
1.public final ThreadGroup getThreadGroup()返回该线程的线程组
2.public ThreadGroup(String name)设置线程组名称
3.public Thread(ThreadGroup,Runnable target,String name)给每一个子线程设置线程组名称
package threadgroup;
public class ThreadGroupDemo {
public static void main(String[] args) {
//线程组:一个线程的集合
method1();
method2();
}
//给每一个子线程设置线程名称
private static void method2() {
//public ThreadGroup(String name)构造一个新线程组
ThreadGroup tg = new ThreadGroup("这是一个新的线程组") ;
//创建资源对象
MyRunnable t1 = new MyRunnable();
//创建线程类对象,并且将线程组对象作为参数进行传递,就使用Thread类的构造方法
//public Thread(ThreadGroup group,Runnable target ,String name){}
Thread th1 = new Thread(tg, t1, "线程1") ;
Thread th2 = new Thread(tg, t1, "线程2") ;
//public final ThreadGroup getThreadGroup()返回该线程的线程组
ThreadGroup tg1 = th1.getThreadGroup() ;
ThreadGroup tg2 = th2.getThreadGroup() ;
System.out.println(tg1.getName());
System.out.println(tg2.getName());
tg.setDaemon(true) ;//将线程组中的所有的线程都设置为守护线程(后台线程)
}
private static void method1() {
// 获取多个线程所在的线程组名称
//创建资源对象
MyRunnable tg = new MyRunnable();
//创建线程类对象
Thread t1 = new Thread(tg);
Thread t2 = new Thread(tg);
//获取t1和t2所在的线程名称
//获取线程组对象
//public final ThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
String name1 = tg1.getName();
String name2 = tg2.getName();
//子线程默认的线程组名称:main线程
System.out.println(name1);//main
System.out.println(name2);//main
//所有的线程它的默认线程组名称就是main
System.out.println(Thread.currentThread().getThreadGroup().getName());
}
}
package threadgroup; public class MyRunnable implements Runnable { @Override public void run() { while(true){ for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"---"+i); } } } }三.线程池
线程池的好处:节约成本,很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用!
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
1)public static ExecutorService
newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。
ExecutorsService :接口中的方法
2)Future<?>
submit(Runnable task)
<T> Future<T> submit(Callable<T> task)package threadpool;
public class MyRunnable implements Runnable {
@Override
public void run() {
while(true){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
package threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorDemo { public static void main(String[] args) { //创建线程池对象 //public static ExecutorService newFixedThreadPool(int nThreads) ExecutorService pool = Executors.newFixedThreadPool(2); //使用submit(Runnable target):提交多个任务 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //结束线程池 pool.shutdown(); } }多线程实现的方式三(实际开发中很少用)
创建线程池对象 实现callable接口
package callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 多线程程序的实现方式3:(实际开发中很少用到!)
* public static ExecutorService newFixedThreadPool(int nThreads)
Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnabl e对象或者Callable对象代表的线程。它提供了如下方法
ExecutorsService :接口中的方法
<T> Future<T> submit(Callable<T> task)
* @author Apple
*/
public class CallableDemo {
public static void main(String[] args) {
// 创建线程池对象
ExecutorService threadpool = Executors.newFixedThreadPool(2);
//提交Callable任务
threadpool.submit(new MyCallable());
threadpool.submit(new MyCallable());
//结束线程池
threadpool.shutdown();
}
}
package callable; import java.util.concurrent.Callable; public class MyCallable implements Callable<Object> { @Override public Object call() throws Exception { for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } return null; } }四.多线程中的匿名内部类的方式
格式:new 类名(具体类,抽象类),接口(){
重写/实现方法;
}
匿名内部类的本质:继承了该类或者是实现该接口的子类对象!
public class ThreadDemo {
public static void main(String[] args) {
//继承自Thread类
new Thread(){
@Override
public void run() {
//for循环
for(int x = 0 ; x <100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}.start() ;//启动线程
//Runnable接口的方式
new Thread(new Runnable() {
@Override
public void run() {
//for循环
for(int x = 0 ; x < 100 ; x ++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}).start() ;
}五.定时器Timer
常用的方法:
public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
public void schedule(TimerTask task, long delay, long period)在多少毫秒后,执行任务,并且每个多少毫秒重复执行
public void cancel()终止此计时器,丢弃所有当前已安排的任务
TimeTask是一个抽象类,自定义一个类实现它
练习:在指定的时间内删除当前项目下Demo文件夹中的内容
package timer;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String[] args) throws ParseException {
//创建Timer定时器
Timer t = new Timer();
//定义一个文本日期格式
String dateStr = "2017-12-8 16:50:00";
//解析成Date对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//解析方法
Date date = sdf.parse(dateStr);
//public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
//调用定时器在指定的时间内执行某个任务
t.schedule(new DeleteFolder(), date);
}
}
//删除Demo文件夹
class DeleteFolder extends TimerTask{
@Override
public void run() {
// 封装当前项目下的Demo文件
File srcFolder = new File("demo");
deleteFolder(srcFolder);
}
//递归删除
private void deleteFolder(File srcFolder) {
// 获取当前strFolder下面的所以文件及文件夹
File[] fileArray = srcFolder.listFiles();
//对该对象非空判断
if(fileArray!=null){
//增强for遍历
for(File file : fileArray){
//判断file对象是否是文件夹
if(file.isDirectory()){
//继续回到删除目录的方法
deleteFolder(file);
}else{
//不是目录,是文件直接删除
System.out.println(file.getName()+"---"+file.delete());
}
}
System.out.println(srcFolder.getName()+"---"+srcFolder.delete());
}
}
}
相关文章推荐
- day25(单例模式,多线程通信,线程组,线程状态,线程池,工厂模式)
- Java基础 - 单例(饿汉、懒汉),Runtime类,Timer,线程通信,互斥锁,线程组,线程五种状态,线程池,工厂模式,GUI,适配器设计模式
- java多线程学习总结之二:线程状态的转换
- 【转】线程的7种状态及相互转换
- [置顶] 线程状态转换说明
- 【转载】Java并发编程2.1:线程状态转换
- 线程中的状态转换和Thread 中的sleep()方法
- 线程状态的转换
- 线程状态的转换
- Java线程:线程状态的转换
- 线程状态转换
- Java编程体验:线程的7种状态及相互转换(图)
- (48)Java学习笔记——多线程 / 线程间通信 / 线程组 / 线程池 /
- Java_基础—线程组和线程池的概述和使用以及线程的生命周期
- 异常信息:CLR无法从COM 上下文0x645e18 转换为COM上下文0x645f88,这种状态已持续60秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作.这种情况通常会影响到性能,甚至可能导致应用程序不响应或者使用的内存随时间不断累积
- 线程状态的转换
- java 线程5 线程的状态及相互转换
- 线程的几种状态转换
- 线程的五种状态与线程池的知识点
- day10 反射创建数组 线程的基本概念 线程的编写和启动方式 线程的运行状态以及状态转换方法 线程的调度和优先级设置