线程的方法:
.isAlive():判断线程是否还活着,即线程是否还未中止。
.getPriority():获得线程的优先级数值。
.setPriority():设置线程的优先级。
.setName():设置线程的名字。
.getName():获取线程名字。
.currentThread():获取当前正在运行的线程对象。
public class MyThread implements Runnable {
private boolean flag =true;
private int num =;
@Override
public void run() {
while(flag){
System.out.println(Thread.currentThread().getName()+"-->"+num++);
}
}
public void stop(){//停止线程的方法
this.flag=!this.flag;
}
}
/**
Thread.currentThread() :当前线程
setName():设置名称
getName():获取名称
isAlive():判断状态
*/
public class InfoDemo01 {
public static void main(String[] args) throws InterruptedException {
MyThread it =new MyThread();
Thread proxy =new Thread(it,"挨踢");
proxy.setName("test");
System.out.println(proxy.getName());
//Thread.currentThread()的currentThread()是一个静态方法,写在哪个线程里面就代表哪个线程。
System.out.println(Thread.currentThread().getName()); //main
proxy.start();
System.out.println("启动后的状态:"+proxy.isAlive());
Thread.sleep();//main阻塞,proxy仍然在跑。
it.stop();//cpu不一定马上停止它,它有延缓的时间。
Thread.sleep();
System.out.println("停止后的状态:"+proxy.isAlive());
}
}
/**
* 优先级:概率,不是绝对的先后顺序
MAX_PRIORITY 10
NORM_PRIORITY 5 (默认)
MIN_PRIORITY 1
setPriority()
getPriority()
*/
public class InfoDemo02 {
public static void main(String[] args) throws InterruptedException {
MyThread it1 =new MyThread();
Thread p1 =new Thread(it1,"挨踢1");
MyThread it2 =new MyThread();
Thread p2 =new Thread(it2,"挨踢2");
p1.setPriority(Thread.MIN_PRIORITY); //设置优先级,优先级高则执行的概率高。
p2.setPriority(Thread.MAX_PRIORITY);//设置优先级
p1.start();
p2.start();
Thread.sleep();
it1.stop();
it2.stop();
}
}
线程的同步(获得方法的锁):
同步也称为并发,由于有多条路径,就存在多个线程访问同一个资源,为了确保这份资源安全,因此对其加入同步,因此就是线程安全。
线程安全与不安全是在多线程访问的情况下,是为了确保资源正确。
synchronized代码块处多个线程进来的时候只能一个一个线程的通过这个代码处,其余线程只能等待前一个线程运行完这个代码处后才能运行这个代码,否则线程只能在这个代码处停止执行。
synchronized -> 任何线程访问这个方法要先获得这个方法的锁。
.同步块
synchronized(引用类型|this|类.class){}
.同步方法
synchronized声明方法。
/*凡是线程安全的效率会低,看到效率低的用时长的则线程安全反之时间短的不安全*/
public class SynDemo01 {
public static void main(String[] args) {
//真实角色
Web12306 web= new Web12306();
//3个代理,代理的是同一份资源Web12306的对象web。
Thread t1 =new Thread(web,"路人甲");
Thread t2 =new Thread(web,"黄牛已");
Thread t3 =new Thread(web,"攻城师");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
/**
* 线程安全的类
*/
class Web12306 implements Runnable {
private int num =;
private boolean flag =true;
@Override
public void run() {
while(flag){
test1();test2();test3();test4();test5();test6();
}
}
public void test6(){
if(num<=){
flag=false; //跳出循环
return ;
}
//a b c
synchronized(this){
try {
Thread.sleep(); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
}
//线程不安全 锁定资源不正确
public void test5(){
//a b c
synchronized((Integer)num){//int是基本类型要手动包装成引用类型才能通过语法检查,所以一般要锁定共同访问的资源对象。
if(num<=){
flag=false; //跳出循环
return ;
}
try {
Thread.sleep(); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
}
//锁定范围过小 线程不安全
public void test4(){
//num=1,abc都在这里等,a进去出来后,b再进去,
synchronized(this){
//b
if(num<=){
flag=false; //跳出循环
return ;
}
}
//a出来了b进去了,由于下面有延时a仍然在等,有可能ab同时到达此处,故num会减2次。所以num会为0.
try {
Thread.sleep(); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}//a -->1
//线程安全 锁定正确
public void test3(){
//a b c
synchronized(this){//同步块,this形参只能是引用类型。this指的是Web12306对象,Web12306对象在同一个时刻只能被一个线程使用。
if(num<=){
flag=false; //跳出循环
return ;
}
try {
Thread.sleep(); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
}
//线程安全 锁定正确,效率低因为有等待,一个线程进入这个方法后其余线程只能等待。
public synchronized void test2(){//a.b.c3个线程同时访问这个方法,a拿到锁,a出去之后bc才能进来。
if(num<=){
flag=false; //跳出循环
return ;
}
try {
Thread.sleep(); //模拟 延时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}
//线程不安全
public void test1(){
if(num<=){//num=1时,当a、b、c,d依次进来后依次开始睡眠。
flag=false; //跳出循环
return ;
}
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
}//a醒了以后带走了1,b醒了以后带走了0,c醒了以后带走了-1,d醒了以后带走了-2。
}
单例设计模式:
对象由类内部自己创建,外部只能使用这一个对象。确保一个类只有一个对象,外部不能创建对象。
垃圾回收gc只有一个,在任何地方都是对其引用而已。
单例设计模式步骤:
、构造器私有化,避免外部直接创建对象
、声明一个私有的静态变量
、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
/**
* 在单线程里面,创建的多个单例的对象的地址是一样的,
* 多线程的时候要想创建的单例对象是同一个则要在单例中创建这个对象的时候加入同步。
*/
/**
* 单例设计模式:确保一个类只有一个对象
*/
public class SynDemo02 {
public static void main(String[] args) {
JvmThread thread1 = new JvmThread();
JvmThread thread2 = new JvmThread();
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));
}
}
/**
* 单例设计模式
* 外部使用时确保一个类只有一个对象,对象由类内部自己创建,外部只能使用这一个对象,外部不能创建对象。
* 懒汉式 ,getInstance()是经典的双重检查。
* 1、构造器私有化,避免外部直接创建对象
* 2、声明一个私有的静态变量
* 3、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
*/
class Jvm {
//声明一个私有的静态变量
private static Jvm instance =null;
//构造器私有化,避免外部直接创建对象
private Jvm(){//自己写了就不会自动创建了,不管你写的是有参还是无参的构造器。
}
//创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
public static Jvm getInstance(long time){
// c d e -->效率 提供 已经存在对象的访问效率
if(null==instance){//这里加判断是为了如果对象已经存在则直接取,不用进同步快,因为同步快要等。
// a b,如果对象不存在则要创建对象,创建对象的时候为了避免多个线程创建多个对象则要加同步快,
synchronized(Jvm.class){//静态方法里面没有this,因为this是这个对象,静态方法时还没有对象。
if(null==instance ){//这里判空是开始没有对象的时候多个线程进入同步快代码之上,有一个进来后创建了,另一个进来后就不用创建了。
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
}
}//a
return instance;
}
public static Jvm getInstance3(long time){//效率不高,和锁住方法的效率差不多。
//a b c d e -->效率不高 c 因为存在对象也需要等待,任何时候获取这个对象都需要等待。
synchronized(Jvm.class){
if(null==instance ){
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
return instance;
}
}
public static Jvm getInstance1(long time){//没有加同步,多个线程会创建多个单例的对象。
if(null==instance ){
//a,b同时进来则会创建多个对象。
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
return instance;
}
public static synchronized Jvm getInstance0(long time){//锁住方法,效率低。
if(null==instance ){
try {
Thread.sleep(time); //延时 ,放大错误
} catch (InterruptedException e) {
e.printStackTrace();
}
instance =new Jvm();
}
return instance;
}
}
任何一个类在jvm或者类加载器中都有一个模板,只要你用到它再去这个模板里面访问。
/**
* 单例创建的方式
* 1、懒汉式
* 1)、构造器私有化
* 2)、声明私有的静态属性
* 3)、对外提供访问属性的静态方法,确保该对象存在
*/
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;
}
}
/**
* 饿汉式
1)、构造器私有化
* 2)、声明私有的静态属性,同时创建该对象
* 3)、对外提供访问属性的静态方法
*/
class MyJvm2 {
private static MyJvm2 instance =new MyJvm2();//类加载时创建
private MyJvm2(){
}
public static MyJvm2 getInstance (){
return instance;
}
}
/**
* 类在使用的时候加载 ,延缓加载时间
*/
class MyJvm3 {//加载MyJvm3时不会加载JVMholder类。
private static class JVMholder{//内部类
private static MyJvm3 instance =new MyJvm3();
}
private MyJvm3(){
}
//加载MyJvm3时还没有调用还没有调用getInstance (),就没有涉及JVMholder类,
//调用getInstance ()方法时涉及JVMholder类就会加载JVMholder类,同时生成MyJvm3的实例。
public static MyJvm3 getInstance (){
return JVMholder.instance;
}
}
过多的同步方法可能造成死锁:
/**
* 过多的同步方法可能造成死锁
* 一手给钱一手给货,你不给钱我不给货,你不给货我不给钱。
*/
public class SynDemo03 {
public static void main(String[] args) {
Object g =new Object();
Object m = new Object();
//同步同一份资源g、m
Test1 t1 =new Test1(g,m);
Test2 t2 = new Test2(g,m);
Thread proxy1 = new Thread(t1);
Thread proxy2 = new Thread(t2);
proxy1.start();//t1的run方法
proxy2.start();//t2的run方法
}
}
class Test1 implements Runnable{
Object goods ;
Object money ;
public Test1(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true){
test();
}
}
public void test(){
synchronized(goods){
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(money){
}
}
System.out.println("一手给钱");
}
}
class Test2 implements Runnable{
Object goods ;
Object money ;
public Test2(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true){
test();
}
}
public void test(){
synchronized(money){
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(goods){
}
}
System.out.println("一手给货");
}
}
生产者消费者模式(解决多线程死锁的问题):
要么生产者生产消费者等待,要么消费者消费生产者等待。
信号灯法:
/**
一个场景,共同的资源
生产者消费者模式-- 信号灯法
wait() :等待,释放锁 ,
sleep(): 不释放锁,
notify()/notifyAll():唤醒,
wait()和notify()/notifyAll()只能 与 synchronized一起使用。
*/
public class Movie {//电影类
private String pic ;
//信号灯
//flag -->T 生产生产,消费者等待 ,生产完成后通知消费
//flag -->F 消费者消费 生产者等待, 消费完成后通知生产
private boolean flag =true;
/**
* 播放
* @param pic
*/
public synchronized void play(String pic){
if(!flag){ //生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//开始生产
try {
Thread.sleep();//生产耗费了500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产了:"+pic);
//生产完毕
this.pic =pic;
//通知消费
this.notify();//唤醒等待线程
//生产者停下
this.flag =false;
}
public synchronized void watch(){
if(flag){ //消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//开始消费
try {
Thread.sleep();//消费所花时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费了"+pic);
//消费完毕
//通知生产
this.notifyAll();//唤醒等待线程
//消费停止
this.flag=true;
}
}
/**
* 生产者
*/
public class Player implements Runnable {
private Movie m ;
public Player(Movie m) {
super();
this.m = m;
}
@Override
public void run() {
for(int i=;i<;i++){
if(==i%){
m.play("左青龙");
}else{
m.play("右白虎");
}
}
}
}
/**
* 消费者
*/
public class Watcher implements Runnable {
private Movie m ;
public Watcher(Movie m) {
super();
this.m = m;
}
@Override
public void run() {
for(int i=;i<;i++){
m.watch();
}
}
}
public class App {
public static void main(String[] args) {
//共同的资源
Movie m = new Movie();
//多线程对同一份资源的访问
Player p = new Player(m);
Watcher w = new Watcher(m);
new Thread(p).start();
new Thread(w).start();
/*生产了:左青龙
消费了左青龙
生产了:右白虎
消费了右白虎
生产了:左青龙
消费了左青龙
生产了:右白虎
消费了右白虎
生产了:左青龙
消费了左青龙
生产了:右白虎
消费了右白虎
生产了:左青龙
消费了左青龙*/
}
}