Java实例——线程

1、查看线程存活状态
Thread.isAlive()
Thread.getName()

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            printMsg();
        }
    }

    public static void printMsg(){
        Thread thread = Thread.currentThread();
        //Thread.getName()	获取线程名称
        System.out.println("name=["+thread.getName()+"]");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.setName("MyThread");	//修改线程名称
        System.out.println("before start(),the Thread Alive = " + myThread.isAlive());//判断线程存活状态
        myThread.start();
        System.out.println("just after start(),the Thread Alive = " + myThread.isAlive());
        for (int i = 0; i < 10; i++) {
            printMsg();
        }
        System.out.println("the end of Thread Alive = " + myThread.isAlive());
    }
}

输出结果

before start(),the Thread Alive = false
just after start(),the Thread Alive = true
name=[main]
name=[main]
name=[main]
name=[main]
name=[MyThread]
name=[main]
name=[main]
name=[main]
name=[main]
name=[main]
name=[main]
name=[MyThread]
the end of Thread Alive = true
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]
name=[MyThread]

2、多线程同步锁
有三种同步锁:synchronize锁,lock锁,volatile锁

  1. synchronize锁是一般情况下Java多线程开发所使用的最常用同步锁。
  2. lock锁同样是常见同步锁。
  3. volatile锁是一种轻量同步锁,能够减轻同步锁所带来的的资源消耗,但只能所用在变量上。

lock锁与synchronize锁的区别:

  1. 两者都是可重入锁,自己可以再次获取自己的内部锁。
  2. synchronized是依赖于虚拟机的,而Lock锁依赖JDK。
  3. synchronized锁可以自动释放锁,而Lock锁必须要手动释放锁。
  4. synchronized锁的两个线程1和线程2,如果当前线程1获得锁,线程2等待,如果线程1阻塞,线程2会一致等待下去,而Lock锁不一定会等下去,如果尝试获几次取不到锁,线程2可以不用一直等待就结束了。

synchronize锁的使用场景:卖票

class MyThread extends Thread{
    public static void main(String[] args) {
        Ticket ticket=new Ticket();
        Thread thread = new Thread(ticket,"售票员小张");
        thread.start();

        Thread thread1 = new Thread(ticket,"售票员小刘");
        thread1.start();
    }
}
//票务系统
class Ticket implements Runnable {
    //总票数
    private int ticketCount = 40;
    
    @Override
    public void run() {
        while (true) {
        	//对票务类进行同步锁,避免线程产生脏数据
            synchronized (Ticket.class) {
                if (ticketCount > 0) {
                    try {
                        //小张在出票的时候被领导叫走了
                        //这个时候呢,小刘也要卖这张票
                        //线程睡眠是在模拟网络延迟的情况
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在售票,剩余" + (--ticketCount));
                }
            }
        }
    }
}

输出结果

售票员小张正在售票,剩余39
售票员小张正在售票,剩余38
售票员小张正在售票,剩余37
售票员小张正在售票,剩余36
售票员小刘正在售票,剩余35
售票员小刘正在售票,剩余34
售票员小刘正在售票,剩余33
售票员小刘正在售票,剩余32
售票员小刘正在售票,剩余31
售票员小刘正在售票,剩余30
售票员小刘正在售票,剩余29
售票员小刘正在售票,剩余28
售票员小刘正在售票,剩余27
售票员小刘正在售票,剩余26
售票员小刘正在售票,剩余25
售票员小刘正在售票,剩余24
售票员小刘正在售票,剩余23
售票员小刘正在售票,剩余22
售票员小刘正在售票,剩余21
售票员小刘正在售票,剩余20
售票员小张正在售票,剩余19
售票员小张正在售票,剩余18
售票员小刘正在售票,剩余17
售票员小刘正在售票,剩余16
售票员小刘正在售票,剩余15
售票员小刘正在售票,剩余14
售票员小刘正在售票,剩余13
售票员小刘正在售票,剩余12
售票员小刘正在售票,剩余11
售票员小刘正在售票,剩余10
售票员小刘正在售票,剩余9
售票员小刘正在售票,剩余8
售票员小刘正在售票,剩余7
售票员小刘正在售票,剩余6
售票员小刘正在售票,剩余5
售票员小刘正在售票,剩余4
售票员小刘正在售票,剩余3
售票员小刘正在售票,剩余2
售票员小张正在售票,剩余1
售票员小刘正在售票,剩余0

Lock锁使用场景:卖票

class MyThread extends Thread{
    public static void main(String[] args) {
        //创建锁对象
        Lock lock=new ReentrantLock();
        //创建要执行的任务
        Ticket ticket=new Ticket(lock);

        //创建线程并开启线程
        Thread t1=new Thread(ticket,"售票员张小飞");
        t1.start();

        Thread t2=new Thread(ticket,"售票员关小羽");
        t2.start();
    }
}

class Ticket implements Runnable {
    private Lock lock;
    private int count = 40;

    public Ticket(Lock lock) {
        this.lock = lock;
    }
    
    @Override
    public void run() {
        while (true) {
            //使用lock锁进行加锁
            lock.lock();
            if (count > 0) {
                try {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + "售出一张票,剩余" + (--count) + "张");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }else{
                System.out.println("售票结束");
                System.exit(0);
            }
    }
}

输出结果

售票员张小飞售出一张票,剩余39张
售票员张小飞售出一张票,剩余38张
售票员张小飞售出一张票,剩余37张
售票员张小飞售出一张票,剩余36张
售票员张小飞售出一张票,剩余35张
售票员张小飞售出一张票,剩余34张
售票员张小飞售出一张票,剩余33张
售票员张小飞售出一张票,剩余32张
售票员张小飞售出一张票,剩余31张
售票员张小飞售出一张票,剩余30张
售票员张小飞售出一张票,剩余29张
售票员张小飞售出一张票,剩余28张
售票员张小飞售出一张票,剩余27张
售票员张小飞售出一张票,剩余26张
售票员张小飞售出一张票,剩余25张
售票员张小飞售出一张票,剩余24张
售票员张小飞售出一张票,剩余23张
售票员张小飞售出一张票,剩余22张
售票员张小飞售出一张票,剩余21张
售票员张小飞售出一张票,剩余20张
售票员张小飞售出一张票,剩余19张
售票员张小飞售出一张票,剩余18张
售票员张小飞售出一张票,剩余17张
售票员张小飞售出一张票,剩余16张
售票员张小飞售出一张票,剩余15张
售票员张小飞售出一张票,剩余14张
售票员张小飞售出一张票,剩余13张
售票员张小飞售出一张票,剩余12张
售票员张小飞售出一张票,剩余11张
售票员张小飞售出一张票,剩余10张
售票员张小飞售出一张票,剩余9张
售票员张小飞售出一张票,剩余8张
售票员张小飞售出一张票,剩余7张
售票员张小飞售出一张票,剩余6张
售票员张小飞售出一张票,剩余5张
售票员张小飞售出一张票,剩余4张
售票员张小飞售出一张票,剩余3张
售票员张小飞售出一张票,剩余2张
售票员张小飞售出一张票,剩余1张
售票员张小飞售出一张票,剩余0张
售票结束

我们可以看到使用Lock锁之后,另一线程无法调用run方法,一直处于等待,在尝试运行run()方法几次之后,结束了另一进程。

3、线程优先级
setPriority(int priority)

class MyThread extends Thread{
    private int countDown = 5;
    private volatile double d = 0;  //同步变量d

    public MyThread(int priority) {
        setPriority(priority);  //设置当前线程优先级
        start();    //开启当前线程
    }

    @Override
    public String toString() {
        return super.toString() + ":" + countDown;
    }

    @Override
    public void run() {
        synchronized(this){
            while (true){
                for (int i = 0; i < 5000; i++) {
                    d = d + (Math.PI + Math.E) / i;
                    System.out.println(this);
                    if (--countDown == 0) return;
                }
            }
        }
    }

    public static void main(String[] args) {
        new MyThread(Thread.MAX_PRIORITY);
        for (int i = 1; i < 5; i++)
            new MyThread(Thread.MIN_PRIORITY);
    }
}

输出结果

Thread[Thread-0,10,main]:5
Thread[Thread-1,1,main]:5
Thread[Thread-2,1,main]:5
Thread[Thread-3,1,main]:5
Thread[Thread-1,1,main]:4
Thread[Thread-0,10,main]:4
Thread[Thread-1,1,main]:3
Thread[Thread-3,1,main]:4
Thread[Thread-4,1,main]:5
Thread[Thread-2,1,main]:4
Thread[Thread-4,1,main]:4
Thread[Thread-3,1,main]:3
Thread[Thread-1,1,main]:2
Thread[Thread-0,10,main]:3
Thread[Thread-1,1,main]:1
Thread[Thread-3,1,main]:2
Thread[Thread-4,1,main]:3
Thread[Thread-2,1,main]:3
Thread[Thread-4,1,main]:2
Thread[Thread-3,1,main]:1
Thread[Thread-0,10,main]:2
Thread[Thread-4,1,main]:1
Thread[Thread-2,1,main]:2
Thread[Thread-0,10,main]:1
Thread[Thread-2,1,main]:1

4、死锁问题及解决方案

  • 死锁的情形: 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
  • 死锁产生必要条件:
    1. 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用。
    2. 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
    3. 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
    4. 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
  • 解决死锁方案
    一种是synchronized同步锁,另一种是Lock显式锁
    为避免死锁,采用信号量控制多线程程序,Semaphore类是用来创建信号量对象的

使用Semaphore控制多线程

public class UnLockTest {
    public static String obj1 = "obj1";
    public static final Semaphore a1 = new Semaphore(1);	//设置a1信号量为1
    public static String obj2 = "obj2";
    public static final Semaphore a2 = new Semaphore(1);	//设置a2信号量为1

    public static void main(String[] args) {
        LockAa la = new LockAa();
        new Thread(la).start();
        LockBb lb = new LockBb();
        new Thread(lb).start();
    }
}
class LockAa implements Runnable {
    public void run() {
        try {
            System.out.println(new Date().toString() + " LockA 开始执行");
            while (true) {
            	//tryAcquire(1, TimeUnit.SECONDS) 1秒尝试请求获取线程许可,TimeUnit.SECONDS 获取秒数
                if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
                    System.out.println(new Date().toString() + " LockA 锁住 obj1");
                    //尝试获取a1线程后,尝试获取a2线程
                    if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
                        System.out.println(new Date().toString() + " LockA 锁住 obj2");
                        Thread.sleep(60 * 1000); // do something
                    }else{
                        System.out.println(new Date().toString() + "LockA 锁 obj2 失败");
                    }
                }else{
                    System.out.println(new Date().toString() + "LockA 锁 obj1 失败");
                }
                UnLockTest.a1.release(); // 释放a1信号量
                UnLockTest.a2.release(); //	释放a2信号量
                Thread.sleep(1000); // 马上进行尝试,现实情况下do something是不确定的
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class LockBb implements Runnable {
    public void run() {
        try {
            System.out.println(new Date().toString() + " LockB 开始执行");
            while (true) {
                if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
                    System.out.println(new Date().toString() + " LockB 锁住 obj2");
                    if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
                        System.out.println(new Date().toString() + " LockB 锁住 obj1");
                        Thread.sleep(60 * 1000); // do something
                    }else{
                        System.out.println(new Date().toString() + "LockB 锁 obj1 失败");
                    }
                }else{
                    System.out.println(new Date().toString() + "LockB 锁 obj2 失败");
                }
                UnLockTest.a1.release();
                UnLockTest.a2.release();
                Thread.sleep(10 * 1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果

Thu Feb 23 02:55:40 CST 2023 LockB 开始执行
Thu Feb 23 02:55:40 CST 2023 LockA 开始执行
Thu Feb 23 02:55:40 CST 2023 LockA 锁住 obj1
Thu Feb 23 02:55:40 CST 2023 LockB 锁住 obj2
Thu Feb 23 02:55:41 CST 2023LockB 锁 obj1 失败
Thu Feb 23 02:55:41 CST 2023LockA 锁 obj2 失败
Thu Feb 23 02:55:42 CST 2023 LockA 锁住 obj1
Thu Feb 23 02:55:42 CST 2023 LockA 锁住 obj2
Thu Feb 23 02:55:51 CST 2023 LockB 锁住 obj2
Thu Feb 23 02:55:51 CST 2023 LockB 锁住 obj1

使用信号量控制多线程锁的步骤
步骤一:创建Semaphore对象

public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static final Semaphore a1 = new Semaphore(1);	//设置1个资源数量
public static final Semaphore a2 = new Semaphore(1);	//设置1个资源数量

步骤二:显式Lock创建

Lock lock1 = new Lock();
Lock lock2 = new Lock();

步骤三:创建线程

new Thread(lock1).start();
new Thread(lock2).start();

步骤四:线程类创建

class ThreadA implements Runnable{
	public void run() throws Exception{
		while(true){
			if(UnLockTest.a1.tryAcquire(1,TimeUnit.SECONDS)){
				System.out.println(new Date().toString() + " lock1 锁住 obj1");
				if(UnLockTest.a2.tryAcquire(1,TimeUnit.SECONDS)){
					System.out.println(new Date().toString() + " lock1 锁住 obj2");
					Thread.sleep(60*1000);
				}
			}else{
               System.out.println(new Date().toString() + "lock1 锁 obj1 失败");
            }
            UnLockTest.a1.release(); // 释放a1信号
            UnLockTest.a2.release();	//释放a2信号
            Thread.sleep(1000); // 空出信号量为ThreadB锁对象obj1,obj2    
		}
	}
}
class ThreadB implements Runnable{
	public void run() throws Exception{
		while(true){
			if(UnLockTest.a1.tryAcquire(1,TimeUnit.SECONDS)){
				System.out.println(new Date().toString() + " lock2 锁住 obj1");
				if(UnLockTest.a2.tryAcquire(1,TimeUnit.SECONDS)){
					System.out.println(new Date().toString() + " lock2 锁住 obj2");
					Thread.sleep(60*1000);
				}
			}else{
               System.out.println(new Date().toString() + "lock2 锁 obj1 失败");
            }
            UnLockTest.a1.release(); //释放a1信号
            UnLockTest.a2.release(); //释放a2信号
            Thread.sleep(1000); // 空出信号量为ThreadA锁对象obj1,obj2    
		}
	}
}

输出结果

Thu Feb 23 03:41:41 CST 2023 LockA 开始执行
Thu Feb 23 03:41:41 CST 2023 LockB 开始执行
Thu Feb 23 03:41:41 CST 2023 LockA 锁住 obj1
Thu Feb 23 03:41:41 CST 2023 LockB 锁住 obj2
Thu Feb 23 03:41:42 CST 2023LockB 锁 obj1 失败
Thu Feb 23 03:41:42 CST 2023LockA 锁 obj2 失败
Thu Feb 23 03:41:43 CST 2023 LockA 锁住 obj1
Thu Feb 23 03:41:43 CST 2023 LockA 锁住 obj2
Thu Feb 23 03:41:52 CST 2023 LockB 锁住 obj2
Thu Feb 23 03:41:52 CST 2023 LockB 锁住 obj1

5、获取线程ID
获取线程ID的方式:getId(),自定义编程ID

public class Main extends Object implements Runnable {
    private ThreadID var;

    public Main(ThreadID v) {
        this.var = v;
    }

    public void run() {
        try {
            print("var getThreadID =" + var.getThreadID());
            Thread.sleep(2000);
            print("var getThreadID =" + var.getThreadID());
        } catch (InterruptedException x) {
        }
    }

    private static void print(String msg) {
        String name = Thread.currentThread().getName();
        System.out.println(name + ": " + msg);
    }

    public static void main(String[] args) {
        ThreadID tid = new ThreadID();
        Main shared = new Main(tid);

        try {
            Thread threadA = new Thread(shared, "threadA");
            threadA.start();

            Thread.sleep(500);

            Thread threadB = new Thread(shared, "threadB");
            threadB.start();

            Thread.sleep(500);

            Thread threadC = new Thread(shared, "threadC");
            threadC.start();
        } catch (InterruptedException x) {
        }
    }
}

//继承ThreadLocal类,是本地线程变量
class ThreadID extends ThreadLocal {
    private int nextID;	//线程ID变量
    public ThreadID() {
        nextID = 10001;	//初始化线程ID
    }
    //同步操作线程ID
    private synchronized Integer getNewID() {
        Integer id = new Integer(nextID);
        nextID++;
        return id;
    }
    
    protected Object initialValue() {
        print("in initialValue()");
        return getNewID();
    }

    public int getThreadID() {
        Integer id = (Integer) get();
        return id.intValue();
    }

    private static void print(String msg) {
        String name = Thread.currentThread().getName();
        System.out.println(name + ": " + msg);
    }
}

输出结果

threadA: in initialValue()
threadA: var getThreadID =10001
threadB: in initialValue()
threadB: var getThreadID =10002
threadC: in initialValue()
threadC: var getThreadID =10003
threadA: var getThreadID =10001
threadB: var getThreadID =10002
threadC: var getThreadID =10003

6、线程挂起
Thread.join() 进入挂起状态,即等待激活状态

public class SleepingThread extends Thread {
    private int countDown = 5;
    private static int threadCount = 0;
    public SleepingThread() {
        super("" + ++threadCount);
        start();
    }

    public String toString() {
        return "#" + getName() + ": " + countDown;
    }

    public void run() {
        while (true) {
            System.out.println(this);
            if (--countDown == 0)
                return;
            try {
                sleep(100);
            }
            catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args)throws InterruptedException {
        for (int i = 0; i < 5; i++)
            new SleepingThread().join();
        System.out.println("线程已被挂起");
    }
}

输出结果

#1: 5
#1: 4
#1: 3
#1: 2
#1: 1
#2: 5
#2: 4
#2: 3
#2: 2
#2: 1
#3: 5
#3: 4
#3: 3
#3: 2
#3: 1
#4: 5
#4: 4
#4: 3
#4: 2
#4: 1
#5: 5
#5: 4
#5: 3
#5: 2
#5: 1
线程已被挂起

7、终止进程
interrupt() ##终止进程
isInterrupt() ##判断是否为终止进程

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        Thread thread = new MyThread();
        thread.start();
        System.out.println(new Date());
        System.out.println("50秒之内按任意键中断线程");
        System.in.read();
        thread.interrupt(); //提前终止程序
        thread.join();  //挂起程序
        System.out.println("程序已退出");
        System.out.println(new Date());
    }
}

输出结果

Thu Feb 23 04:27:01 CST 2023
50秒之内按任意键中断线程
 
程序已退出
Thu Feb 23 04:27:02 CST 2023

8、生产者/消费者问题
需要的是什么?
1、共享存储空间 content

class CubbyHole{
	private int contents;	//空间存储量
	private boolean available = false;	//是否可用
	//获取
	public synchronized int get(){
		while(available == false){
			try{
				wait();
			}catch(Exception e){}
		}
		available = false;
		notifyAll();
		return contents;
	}
	public synchronized void put(int value){
		while(available == true){
			try{
				wait();
			}catch(Exception e){}
		}
		contents = values;
		available = true;
		notifyAll();
	}
}

2、生产者线程 producter

class Consumer extends Thread{
	private CubbyHole cubbyhole;
	private int number;
	public Consumer(CubbyHole c,int number){
		cubbyhole = c;
		this.number = number;
	}
	public void run(){
		int value = 0;
		for(int i = 0;i<10;i++){
			value = cubbyhole.get();
			System.out.println("消费者 #" + this.number+ " got: " + value);
		}
	}
}

3、消费者线程 consumer

public Producer extends Thread{
	private CubbyHole cubbyhole;
	private int number;
	public Producer(CubbyHole c,int number){
		cubbyhole = c;
		this.number = number;
	}
	
	public void run(){
		for(int i = 0; i < 10 ; i++){
			cubbyhole.put(i);
			System.out.println("生产者 #" + this.number + " put: " + i);
	        try {
	            sleep((int)(Math.random() * 100));
	        } catch (InterruptedException e) { }
		}
	}
}

输出结果

消费者 #1 got: 0
生产者 #1 put: 0
生产者 #1 put: 1
消费者 #1 got: 1
生产者 #1 put: 2
消费者 #1 got: 2
生产者 #1 put: 3
消费者 #1 got: 3
生产者 #1 put: 4
消费者 #1 got: 4
生产者 #1 put: 5
消费者 #1 got: 5
生产者 #1 put: 6
消费者 #1 got: 6
生产者 #1 put: 7
消费者 #1 got: 7
生产者 #1 put: 8
消费者 #1 got: 8
生产者 #1 put: 9
消费者 #1 got: 9
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zain_horse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值