多线程——JAVA

一、线程简介:

一个程序可以包括多个子任务,可串/并行,每一个子任务可以称为一个线程,如果一个子任务阻塞,程序会将cpu调度另一个子任务进行工作,这样cpu就可以保留在本程序中,而不是像进程如果被阻塞cpu被调度到别的程序(进程)去。线程可以共享数据,线程通讯更加高效,线程更加轻量、容易切换,多个线程更加容易管理。

二、线程构造

1.线程继续Thread类,并且实现run方法。示例1

2.线程实现Runnable接口,实现run方法,启动时需要Thread类支持。示例2.

两种构造方法的比较:方法一会占继承类的名额,方法二启动时需要Thread类支持,方法二更容易实现多线程中资源共享。

三、线程启动

start方法进行启动,但是不能多次启动;多个线程启动时,其启动的先后顺序是随机的,mian函数可能早于新线程结束(”守护线程“会早于main函数结束),整个程序并不终止。

四、多线程信息共享

1.static变量修饰票。示例3:出现信息不一致,并且卖出103张票。

原因:线程处理会有自己的工作缓存,所以有时候变量改变被其他线程改变,此线程未及时更新。

如示例4这种情况,都是同一个testThread1的对象,只是重新包装了四次而已,,显示卖出128张,存在误差

2.volatile关键字帮助变量一旦更改就及时告知工作缓存区。如示例5,可查看缓存区flag改变及时。

3.synchronized关键字修饰代码块或者函数,实现互斥,一次只能一个线程的进入访问。如示例6,显示买票100次,无误差

五、线程管理

1.线程的五大状态:创建、就绪、运行、阻塞、结束

2.线程的阻塞和唤醒方法:sleep时间一到自己就会醒来,wait/notify/notify等待,需要别人唤醒,join等待另一个线程结束,interrupt中断,向另外的线程发送中断信号,收到中断信号后会阻塞。

3.线程最好自己主动暂停和终止,被动暂停和终止会导致可能不能及时释放资源。如示例7,最好不要用interrupt方法被动终止进程。

4.守护(后台)线程:线程会在run结束或者main函数结束后结束,设置守护线程的方法:将t线程中的setDaemon()方法设置为true.如t.setDaemon(true);

5.线程死锁解决方法:对资源进行等级排序,不要造成两个线程资源所需交叉。

示例1:


public class Thread1 extends Thread{
	public void run()
	{
		System.out.println("hello");
	}
	public static void main(String[] a)
	{
		new Thread1().start();
	}
}

示例2:


public class Thread2 implements Runnable{
	public void run()
	{
		System.out.println("hello");
	}
	public static void main(String[] a)
	{
		new Thread(new Thread2()).start();
	}
}

示例3:


public class ThreadDemo0
{
	public static void main(String [] args)
	{
		new TestThread0().start();
		new TestThread0().start();
		new TestThread0().start();
		new TestThread0().start();
	}
}
class TestThread0 extends Thread  
{
	//private int tickets=100;           //每个线程卖100张,没有共享
	private static int tickets=100;  //static变量是共享的,所有的线程共享
	public void run()
	{
		while(true)
		{
			if(tickets>0)
			{
				System.out.println(Thread.currentThread().getName() +
				" is selling ticket " + tickets);
				tickets = tickets - 1;
			}
			else
			{
				break;
			}
		}
	}
}

示例4:


public class ThreadDemo1
{
	public static void main(String [] args)
	{
		TestThread1 t=new TestThread1();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
	}
}
class TestThread1 implements Runnable
{
	private int tickets=100;
	public void run()
	{
		while(true)
		{
			if(tickets>0)
			{
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				tickets--;
				System.out.println(Thread.currentThread().getName() +" is selling ticket " + tickets);
			}
			else
			{
				break;
			}
				
		}
	}
}

示例5:

public class ThreadDemo2
{
	public static void main(String args[]) throws Exception 
	{
		TestThread2 t = new TestThread2();
		t.start();
		Thread.sleep(2000);
		t.flag = false;
		System.out.println("main thread is exiting");
	}
}

class TestThread2 extends Thread
{
	//boolean flag = true;   //子线程不会停止
	volatile boolean flag = true;  //用volatile修饰的变量可以及时在各线程里面通知
	public void run() 
	{
		int i=0;
		while(flag)
		{
			i++;			
		}
		System.out.println("test thread3 is exiting");
	}	
} 

示例6:


public class ThreadDemo3 {
	public static void main(String[] args) {
		TestThread3 t = new TestThread3();
		new Thread(t, "Thread-0").start();
		new Thread(t, "Thread-1").start();
		new Thread(t, "Thread-2").start();
		new Thread(t, "Thread-3").start();
	}
}

class TestThread3 implements Runnable {
	private volatile int tickets = 100; // 多个 线程在共享的
	String str = new String("");

	public void run() {
		while (true) {
			//synchronized(str){
			sale();
			//}
			try {
				Thread.sleep(100);
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}
			if (tickets <= 0) {
				break;
			}
		}

	}

	public synchronized void sale() { // synchronized标志同步函数,一次只能一个线程进来也可以修饰代码块
		if (tickets > 0) {
			System.out.println(Thread.currentThread().getName() + " is saling ticket " + tickets--);
		}
	}
}

示例7:

package interrupt;

public class InterruptTest {

	public static void main(String[] args) throws InterruptedException {
		TestThread1 t1 = new TestThread1();
		TestThread2 t2 = new TestThread2();

		t1.start();
		t2.start();

		// 让线程运行一会儿后中断
		Thread.sleep(2000);
		t1.interrupt();
		t2.flag = false;
		System.out.println("main thread is exiting");
	}

}

class TestThread1 extends Thread {
	public void run() {
		// 判断标志,当本线程被别人interrupt后,JVM会被本线程设置interrupted标记
		while (!interrupted()) {
			System.out.println("test thread1 is running");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
				break;
			}
		}
		System.out.println("test thread1 is exiting");
	}
}

class TestThread2 extends Thread {
	public volatile boolean flag = true;
	public void run() {
		// 判断标志,当本线程被别人interrupt后,JVM会被本线程设置interrupted标记
		while (flag) {
			System.out.println("test thread2 is running");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("test thread2 is exiting");
	}
}

输出:
test thread1 is running
test thread2 is running
test thread1 is running
test thread2 is running
test thread2 is running
test thread1 is running
main thread is exiting
test thread1 is exiting
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at interrupt.TestThread1.run(InterruptTest.java:27)
test thread2 is exiting

参考中国大学mooc网,《java核心技术》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值