1,java中线程的生命周期和5种状态
经典图
线程的生命周期中有5种状态
01:新建状态 (new 一个线程),就是我们new 一个线程对象,此时线程是新建状态
02:就绪状态(runnable),调用线程的 start()方法,线程就进入了就绪状态 ,调用start方法的线程并不一定会马上就开始执行,就绪状态表示线程做好了准备,随时等待cpu有资源的时候执行。
03:运行状态(running),不多说,就是线程运行状态,
04:阻塞状态(blocked):看上图,线程的阻塞状态有多种情况,阻塞状态就是线程由于某种原因停止了执行,
wait阻塞:等待阻塞,wait是object类的方法,可以指定一个等待的时间,当调用object的notify()或notifyAll()方法时,线程就会从阻塞状态进入到就绪状态,
public final void wait() throws InterruptedException {
wait(0);
}
synchronized阻塞:同步阻塞,线程在执行到synchronized 修饰的代码时,会求获取同步锁对象,当有别的线程占用锁的时候,获取锁对象失败,
就进入到同步阻塞状态
其他阻塞:thread.sleep()方法,join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、
或者I/O处理完毕时,线程重新转入就绪状态。
05:dead死亡状态,线程执行完毕,或者异常退出了,线程就死亡了
2.java中生成一个线程对象的几种方法
01、继承Thread类,重写润方法
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + "正在执行");
}
}
02、实现runnable接口,实现run方法
class MyThreadRun implements Runnable{
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + "正在执行");
}
}
03、实现callable接口,实现call方法,使用这种方法线程会返回一个future对象,可以让线程返回数据
class MyCallable implements Callable<String> {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String call() throws Exception {
return name;
}
}
3.synchronized 关键字
synchronized 修饰同步方法和同步代码块,用来保证在多线程环境下的线程安全,
同步代码块
public class TestSync {
public void print(){
synchronized (this){
for (int i = 0; i < 5; i++) {
System.out.println("TestSync--->"+i);
}
}
}
public static void main(String[] args){
TestSync testSync=new TestSync();
Mythread mt1=new Mythread(testSync);
Mythread mt2=new Mythread(testSync);
mt1.start();
mt2.start();
}
}
class Mythread extends Thread{
private TestSync testSync;
public Mythread(TestSync testSync) {
this.testSync = testSync;
}
@Override
public void run() {
testSync.print();
}
}
执行结果: 可以看到是顺序执行的,在第一个线程获得锁的时候,其他线程就会进入阻塞状态,等待拥有锁对象的线程执行完毕,再去竞争这个锁,
谁抢到了锁,谁就执行,这里的this 表示以当前实例对象为锁,当然你也可以随便new 一个object 来当做所对象
TestSync--->0
TestSync--->1
TestSync--->2
TestSync--->3
TestSync--->4
TestSync--->0
TestSync--->1
TestSync--->2
TestSync--->3
TestSync--->4
去掉同步块
public void print(){
// synchronized (this){
for (int i = 0; i < 5; i++) {
System.out.println("TestSync--->"+i);
}
// }
}
执行结果: 执行的顺序是无序的,两个线程交替执行
TestSync--->0
TestSync--->0
TestSync--->1
TestSync--->2
TestSync--->1
TestSync--->3
TestSync--->2
TestSync--->4
TestSync--->3
TestSync--->4
同步方法: 执行结果和上边相同,这里也是以实例对象为锁对象
public synchronized void print(){
for (int i = 0; i < 5; i++) {
System.out.println("TestSync--->"+i);
}
}
还有一种是修饰static方法,这时是以类对象为同步锁
public static synchronized void print(){
for (int i = 0; i < 5; i++) {
System.out.println("TestSync--->"+i);
}
}
4.wait 和sleep的区别
wait方法和sleep方法都可以让线程休眠指定的时间,区别就是sleep方法不会释放锁,wait会释放出锁
看代码
package threadTest;
/**
* Created by LuTshoes on 2017/8/4 0004.
* lutshoes@163.com
*/
public class TestThread {
Object object = new Object();
public void print() {
synchronized (object) {
for (int i = 0; i < 3; i++) {
if (i == 1) {
try {
object.wait(2000);
//Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "--->" + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
TestThread testThread = new TestThread();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
testThread.print();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
testThread.print();
}
});
t1.start();
Thread.sleep(1000);//让t2线程在t1之后启动
t2.start();
}
}
执行结果: 虽然在print方法里面加上了synchronized所,但是wait方法会释放object锁对象的控制,给了线程t2执行的机会
当前线程:Thread-0--->0
当前线程:Thread-1--->0
当前线程:Thread-0--->1
当前线程:Thread-0--->2
当前线程:Thread-1--->1
当前线程:Thread-1--->2
把wait方法换成sleep方法,执行结果,可以看到线程t1虽然休眠了2秒,执行完成但是t2却没有获得执行的机会,就是因为sleep不会释放锁的占有
当前线程:Thread-0--->0
当前线程:Thread-0--->1
当前线程:Thread-0--->2
当前线程:Thread-1--->0
当前线程:Thread-1--->1
当前线程:Thread-1--->2
thread.yeild 方法
Java线程中的Thread.yield( )方法,译为线程让步。顾名思义,就是说当一个线程使用了这个方法之后,它就会把自己CPU执行的时间让掉,
让自己或者其它的线程运行,注意是让自己或者其他线程运行,并不是单纯的让给其他线程。
yield()的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权;但是,并不能保
证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到“运行状态”继续运行!
举个例子:一帮朋友在排队上公交车,轮到Yield的时候,他突然说:我不想先上去了,咱们大家来竞赛上公交车。然后所有人就一块冲向公交车,
有可能是其他人先上车了,也有可能是Yield先上车了。
但是线程是有优先级的,优先级越高的人,就一定能第一个上车吗?这是不一定的,优先级高的人仅仅只是第一个上车的概率大了一点而已,
最终第一个上车的,也有可能是优先级最低的人。并且所谓的优先级执行,是在大量执行次数中才能体现出来的。
5.java.util.concurrent包
这个包里面有很多在多线程环境下的工具类,比如 executors,executorService,threadLocal,concurrentHashMap
concurrentHashMap 具有hashTabl的功能,
executors类可以帮我们生成各种不同功能的线程池,
package threadTest;
/**
* Created by LuTshoes on 2017/8/3 0003.
* lutshoes@163.com
*/
import org.junit.Test;
import java.util.concurrent.*;
public class TashExecutorHolder {
//创建一个可根据需要创建新线程的线程池,
// 但是在以前构造的线程可用时将重用它们。
// 对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。
private ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。
/**
* newFixedThreadPool的参数指定了可以运行的线程的最大数目,超过这个数目的线程加进去以后,
* 不会运行。其次,加入线程池的线程属于托管状态,线程的运行不受加入顺序的影响。
*/
private ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
//创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
private ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
private ExecutorService callablePool = Executors.newFixedThreadPool(2);
@Test
public void testCachedThreadPool() {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
cachedThreadPool.execute(t1);
cachedThreadPool.execute(t3);
cachedThreadPool.execute(t2);
/* Future<?> submit = cachedThreadPool.submit(t1);
Object o = null;
try {
o = submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(o);*/
}
@Test
public void testSingleThreadPool() {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
singleThreadPool.submit(t1);
singleThreadPool.submit(t2);
singleThreadPool.submit(t3);
singleThreadPool.submit(t4);
}
@Test
public void testFixedThreadPool() {
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
fixedThreadPool.submit(t1);
fixedThreadPool.submit(t2);
fixedThreadPool.submit(t3);
fixedThreadPool.submit(t4);
}
/**
* 带有返回值的线程callable
*/
@Test
public void testCallablePool(){
Future<People> future = callablePool.submit((Callable) () -> {
return new People("lujia");
});
People people = null;
try {
people = future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(people.toString());
}
@Test
public void testCallable(){
MyCallable myCallable = new MyCallable();
myCallable.setName("哈哈");
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + "正在执行");
}
}
class People {
public People(String name) {
this.name = name;
}
private String name;
@Override
public String toString() {
return this.name;
}
}
class MyThreadRun implements Runnable{
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + "正在执行");
}
}
class MyCallable implements Callable<String> {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String call() throws Exception {
return name;
}
}