一.线程操作
1.守护线程(后台线程)(运行main方法的线程是前台线程)
1.1创建:通过线程提供的方法setDaemon来完成
1.2区别:当一个进程结束时,所有正在运行的后台线程都会强制结束(而进程的结束是当一个进程中所有前台线程都结束时结束)
/**
* 守护线程
* 也称后台线程
*
* 默认创建出来的线程都是前台线程,若要设这为后台线程可以通过线程提供的方法setDaemon来完成
*
* 后台线程使用上与前台线程一样,但是在结束时机上有一点是不同的,即:当一个进程结束时,所有正在运行的
* 后台线程都会强制结束。而进程的结束是当一个进程中所有前台线程都结束时结束
*
* 所以将来开发中可以将一直保持运行的任务,但是可以随着程序一同结束的放在后台线程上运行
* @author soft01
*
*/
public class Tread_setDemon {
public static void main(String[] args) {
Thread t1=new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
for(int i=0;i<5;i++){
System.out.println("玩不了了!");
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("破两路更好打是吧");
try {
sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("天辉获胜!");
}
};
Thread t2=new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
while(true){
System.out.println("技不如人,甘拜下风");
try {
sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
t1.start();
/*
* 在线程启动前设置守护线程
*/
t2.setDaemon(true);
t2.start();
}
}
2.static void yield()
使当前线程主动让出当次CPU时间片回到Runnable状态,等待分配时间片
3.void join()
作用:用于等待当前线程结束(抛出InterruptException)—-协调线程同步运行
代码演示
/**
* 线程提供了一个方法:join
* join可以协调线程同步运行
*
*/
public class Thread_join {
//标识是否完成
private static boolean isFinish=false;
public static void main(String[] args) {
/*
* 当一个方法的局部内部类中需要引用该方法的其他局部变量时,该变量必须是final的
*
* 在这里main方法的局部内部类show中想引用main方法的其他局部变量download,那么
* download就必须是final的
* JDK1.8之后由于内存问题被重新定义,不再有这个问题,所有不用再设为final
*/
final Thread download=new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
System.out.println("开始下载:");
/*
* 假装在下载
*/
for(int i=0;i<100;i++){
System.out.println("down:"+i+"%");
try {
sleep(40);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("下载完毕!");
isFinish=true;
}
};
Thread show=new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
System.out.println("开始显示下载内容:");
//等待其他线程
/*
* 当show线程调用download线程的join方法时,
* show线程进入阻塞状态,直到download执行完毕
* 才会解除阻塞继续执行后续代码
*/
try {
download.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(isFinish){
System.out.println("show!");
}else{
throw new RuntimeException("未下载完成");
}
}
};
download.start();
show.start();
}
}
4.多线程并发安全问题
4.1 原因:当多个线程并发访问统一资源时,由于线程切换时机不确定导致代码未按照设计方式的顺序执行导致的逻辑混乱.
4.2 解决方法:
4.2.1 synchronized 修饰方法
多个线程不能同时进入到方法内部执行(当一个方法被synchronized修饰后,那么该方法称为“同步方法”)
4.2.2 同步代码块 (可以更精确的控制需要同步执行的代码片段)
synchronized(同步监视器–锁对象引用){ //锁对象引用一般用this或类名.class
//代码块
}
4.2.3静态方法使用synchronized—–一定具有同步效果
public synchronized static /synchronized/ void dosome(){}
4.2.4互斥锁问题
5.将集合或Map转换为线程安全
5.1 List list=new ArrayList();
list.add(“one”);
…
list=Collections.synchronizedList(list);
5.2 Set<String> set=new HashSet<String>(list);
set=Collections.synchronizedSet(set);
5.3 Map<String,Integer> map=new HashMap<String,Integer>();
map=Collections.synchronizedMap(map);
二.线程池
1.作用:
1.1 控制线程数量
1.2 重用线程
2.Executors.newCachedThreadPool()
创建一个可根据需要创建新线程的线程池(在以前构造的线程可用时将重用它们)
3.Executors.newFixedThreadPool(int nThreads)
创建一个可重用固定线程集合的线程池(以共享的无界队列方式来运行这些线程)
4.Executors.newScheduledThreadPool(int corePoolSize)
创建一个线程池,它可安排在给定延迟后运行命令或定期地执行
5.Executors.newSingleThreadExecutor()
创建一个使用单个worker线程的Executor,以无界队列方式来运行该线程
代码演示
/**
* 线程池
* 线程池主要解决两个问题:
* 1.控制线程数量,因为线程数多了,会导致内存开销大,
* 严重时会导致系统瘫痪,并且由于线程数量多会导致CPU过度切换,
* 拖慢系统响应
* 2.重用线程
*
*/
public class ThreadPoolDemo {
public static void main(String[] args) {
//创建固定大小线程池
ExecutorService threadPool=Executors.newFixedThreadPool(2);
for(int i=0;i<5;i++){
Runnable runn=new Runnable(){
@Override
public void run() {
Thread t=Thread.currentThread();
System.out.println(t.getName()+"正在运行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"运行完毕");
}
};
threadPool.execute(runn);
System.out.println("指派了一个任务");
}
threadPool.shutdown();
System.out.println("停止线程池");
}
}
三.BlockingQueue 双缓冲队列
BlockingQueue内部使用两条队列,可允许两个线程同时向队列一个做存储,一个做取出操作.
—-在保证并发安全的同时提高了队列的存取效率