目录
线程状态
- 新生状态:
用new关键字和 Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable) - 就绪状态:
处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就队列,等待系统为其分配CPU。等待状态并不是执行状态,当系统选定一个等待执行的 Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调度”,一旦获得CPU,线程就进入运行状态并自动调用自己的run方法 - 运行状态:
在运行状态的线程执行自己的run方法中代码,直到调用其他方法而终止、或等待某资源而阻塞或完成任务而死亡。如果在给定的时片内没有执行结束,就会被系统给换下来回到等待执行状态 - 阻塞状态:
处于运行状态的线程在某些情况下,如执行了 sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行 - 死亡状态:
死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个,一个是正常运行的线程完成了它的全部工作;另一个是线程被强制性地终止,如通过执行stop或 destroy方法来终止一个线程(不推荐使用这两个方法。前者会产生异常,后者是强制终止,不会释放锁)
停止线程
- 自然终止:线程体正常执行完毕
- 外部干涉:
1.线程类中定义线程体使用的标识
2.线程体使用该标识
3.提供对外的方法改变标识
4.外部根据条件调用该方法
eg:
public class Demo01 {
public static void main(String[] args) {
Study s = new Study();
new Thread(s).start();
//外部干涉
for (int i = 0; i < 100; i++) {
if(i==50){
s.stop();
}
System.out.println("main"+i);
}
}
}
class Study implements Runnable{
//1.线程类中定义线程体使用的标识
private boolean flag = true;
@Override
public void run() {
//2.线程体使用该标识
while(flag){
System.out.println("study thread");
}
//3.提供对外的方法改变标识
}
public void stop(){
this.flag = false;
}
}
线程阻塞
- join:合并线程
- yield:暂停自己的线程 静态方法
- sleep:休眠,不释放锁 需要解决并发的问题
1.与时间相关:倒计时
2.模拟网络延时
eg:合并线程
/**
* join:合并线程
* @author qiao39gs
*
*/
public class JoinDemo01 extends Thread{
public static void main(String[] args) throws InterruptedException {
JoinDemo01 demo = new JoinDemo01();
Thread t = new Thread(demo); //新生
t.start(); //就绪
//cpu调度运行
for (int i = 0; i < 100; i++) {
if(i==50){
t.join(); //main阻塞
}
System.out.println("main```"+i);
}
}
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("join```"+i);
}
}
}
eg:暂停线程
public class YieldDemo01 extends Thread {
public static void main(String[] args) {
YieldDemo01 demo = new YieldDemo01();
Thread t = new Thread(demo); //新生
t.start(); //就绪
//cpu调度运行
for (int i = 0; i < 1000; i++) {
if(i%20==0){
//暂停本线程main
Thread.yield();
}
System.out.println("main```"+i);
}
}
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println("yield``````````````````"+i);
}
}
}
eg:倒计时
/**
* 倒计时
* 1.10个数,一秒内打印一个
* 2.倒计时
* @author qiao39gs
*
*/
public class SleepDemo01 {
public static void main(String[] args) throws InterruptedException {
Date endTime = new Date(System.currentTimeMillis()+10*1000);
long end = endTime.getTime();
while(true){
//输出
System.out.println(new SimpleDateFormat("mm:ss").format(endTime));
//构建下一秒时间
endTime = new Date(endTime.getTime()-1000);
//等待一秒
Thread.sleep(1000);
//10秒以内继续否则退出
if(end-10000>endTime.getTime()){
break;
}
}
}
public static void test1() throws InterruptedException{
int num = 10;
while(true){
System.out.println(num--);
Thread.sleep(1000); //暂停
if(num<=0){
break;
}
}
}
}
线程基本信息
方法 | 功能 |
---|---|
isAlive() | 判断线程是否还“活”着,即线程是否还未终止 |
getPriority() | 获得线程的优先级数值 |
setPriority() | 设置线程的优先级数值 |
setName() | 给线程一个名字 |
getName() | 取得线程的名字 |
currentThread() | 取得当前正在运行的线程对象也就是取得自己本身 |
eg1:
public class MyThread implements Runnable {
private boolean flag = true;
private int num = 0;
@Override
public void run() {
while(flag){
System.out.println(Thread.currentThread().getName()+"——>"+num++);
}
}
public void stop(){
this.flag = !this.flag;
}
}
/**
* currentThread():当前线程
* setName:设置名称
* getName:获取名称
* isAlive:判断状态
* @author qiao39gs
*
*/
public class InfoDemo01 {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
Thread proxy = new Thread(t1,"AAA");
proxy.setName("test");
System.out.println(proxy.getName());
System.out.println(Thread.currentThread().getName()); //main
proxy.start();
System.out.println("启动后的状态:"+proxy.isAlive());
Thread.sleep(20);
t1.stop();
Thread.sleep(10);
System.out.println("停止后的状态:"+proxy.isAlive());
}
}
eg2:
/**
* 优先级:概率,不是绝对的先后顺序
*
* MAX_PRIORITY 10
* NORM_PRIORITY 5(默认)
* MIN_PRIORITY 1
*
* setPriority()
* getPriority()
* @author qiao39gs
*
*/
public class InfoDemo02 {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
Thread p1 = new Thread(t1,"AAA");
MyThread t2 = new MyThread();
Thread p2 = new Thread(t1,"BBB");
p1.setPriority(Thread.MIN_PRIORITY); //设置优先级
p2.setPriority(Thread.MAX_PRIORITY); //设置优先级
p1.start();
p2.start();
Thread.sleep(10);
t1.stop();
t2.stop();
}
}
线程同步
并发 多个线程访问同一份资源 确保资源安全 ——> 线程安全
线程安全会导致效率低下
- 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问
- 由于可以通过 private关键字来保证数据对象只能被方法访问,所以只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块
- 同步方法
synchronized - 同步块
synchronized(引用类型|this|类.class){
}
eg:
public class SynDemo01 {
public static void main(String[] args) {
//真实角色
Web123456 web = new Web123456();
//代理
Thread t1 = new Thread(web,"路人甲");
Thread t2 = new Thread(web,"黄牛乙");
Thread t3 = new Thread(web,"黄牛丙");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
/**
* 线程安全的类
* @author qiao39gs
*
*/
class Web123456 implements Runnable{
private int num = 10;
private boolean flag = true;
@Override
public void run() {
while(flag){
test5();
}
}
//线程不安全,锁定资源不正确
public void test5(){
synchronized((Integer) num){
if(num<=0){
flag = false;
return;
}
try {
Thread.sleep(100); //模拟延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
}
//锁定范围不正确
public void test4(){
synchronized(this){
if(num<=0){
flag = false;
return;
}
}
try {
Thread.sleep(100); //模拟延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
//线程安全,锁定正确
public void test3(){
synchronized(this){
if(num<=0){
flag = false;
return;
}
try {
Thread.sleep(100); //模拟延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
}
//线程安全,锁定正确
public synchronized void test2(){
if(num<=0){
flag = false;
return;
}
try {
Thread.sleep(100); //模拟延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
//线程不安全
public void test1(){
if(num<=0){
flag = false;
return;
}
try {
Thread.sleep(100); //模拟延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
}
单例设计模式
单例设计模式:确保一个类只有一个对象
eg:
/**
* 单例设计模式:确保一个类只有一个对象
* @author qiao39gs
*
*/
public class SynDemo02 {
public static void main(String[] args) {
Jvm jvm1 = Jvm.getInstance();
Jvm jvm2 = Jvm.getInstance();
System.out.println(jvm1);
System.out.println(jvm2);
}
}
/*
* 单例设计模式
* 确保一个类只有一个对象
* 懒汉式
* 1.构造器私有化,避免外部直接创建对象
* 2.声明一个静态变量
* 3.创建一个对外的公共的静态方法访问该变量,如果变量没有对象,创建该对象
*/
class Jvm {
//声明一个私有的静态变量
private static Jvm instance = null;
//构造器私有化,避免外部直接创建对象
private Jvm(){
}
//创建一个对外的公共的静态方法访问该变量,如果变量没有对象,创建该对象
public static Jvm getInstance(){
if(null==instance){
instance = new Jvm();
}
return instance;
}
}
多线程单例模式实现线程安全
eg:单例设计模式,class锁定
/**
* 单例设计模式:确保一个类只有一个对象
* @author qiao39gs
*
*/
public class SynDemo02 {
public static void main(String[] args) {
JvmThread thread1 = new JvmThread(100);
JvmThread thread2 = new JvmThread(100);
thread1.start();
thread2.start();
}
}
class JvmThread extends Thread{
private long time;
public JvmThread() {
}
public JvmThread(long time) {
this.time = time;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建:"+Jvm.getInstance(time));
}
}
/*
* 单例设计模式
* 确保一个类只有一个对象
* 懒汉式 double checking
* 1.构造器私有化,避免外部直接创建对象
* 2.声明一个静态变量
* 3.创建一个对外的公共的静态方法访问该变量,如果变量没有对象,创建该对象
*/
class Jvm {
//声明一个私有的静态变量
private static Jvm instance = null;
//构造器私有化,避免外部直接创建对象
private Jvm(){
}
//创建一个对外的公共的静态方法访问该变量,如果变量没有对象,创建该对象
public static Jvm getInstance(long time){
if(null==instance){ //double checking
synchronized(Jvm.class){
if(null==instance){
try {
Thread.sleep(time); //延时,放大错误
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instance = new Jvm();
}
}
}
return instance;
}
public static Jvm getInstance3(long time){
//效率不高,存在对象也需要等待
synchronized(Jvm.class){
if(null==instance){
try {
Thread.sleep(time); //延时,放大错误
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instance = new Jvm();
}
return instance;
}
}
public static synchronized Jvm getInstance2(long time){
//效率不高
if(null==instance){
try {
Thread.sleep(time); //延时,放大错误
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instance = new Jvm();
}
return instance;
}
public static Jvm getInstance1(long time){
if(null==instance){
try {
Thread.sleep(time); //延时,放大错误
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instance = new Jvm();
}
return instance;
}
}
单例创建的方式
- 懒汉式
1.构造器私有化
2.声明私有的静态属性
3.对外提供访问属性的静态方法,确保该对象存在 - 饿汉式
1.构造器私有化
2.声明私有的静态属性,同时创建对象
3.对外提供访问属性的静态方法,确保该对象存在
eg1:
public class MyJvm {
private static MyJvm instance;
private MyJvm(){
}
public static MyJvm getInstance(){
if(null==instance){ //提供效率
synchronized (MyJvm.class) {
if(null==instance){ //安全
instance = new MyJvm();
}
}
}
return instance;
}
}
eg2:
class MyJvm3 {
public static class JVMholder{
private static MyJvm3 instance = new MyJvm3();
}
private MyJvm3(){
}
public static MyJvm3 getInstance(){
return JVMholder.instance; //类在使用的时候加载,延缓加载时间
}
}