黑马程序员学习日记--多线程

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

一:概述

进程:执行中的程序

每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。

线程: 进程中一个独立的控制单元。

线程在控制着进程的执行。

(一个进程中至少有一个线程)

eg: JVM启动的时候会有一个进程java.exe。该进程中至少有一个线程负责了java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程

Thread 线程:程序中的执行线程。Java虚拟机允许应用程序并发的运行多个执行线程。


二:创建线程:

两种方法:

一:将类声明为Thread的子类,该子类应重写Thread类的run方法。接下来分配并启动该子类的实例。

二:声明实现Runnable接口的类,该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。

start():使线程开始执行。java虚拟机调用该线程的run方法。

多线程具有随机性

run方法:存储线程要运行的代码

多窗口同时售票示例:

class J11_1 
{
	public static void main(String[] args) 
	{
		//新建4个窗口
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		Ticket t3 = new Ticket();
		Ticket t4 = new Ticket();
		
		//开始窗口线程
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
class Ticket extends Thread
{
	//票的总数为40
	private static int num=40;
	public void run()
	{
		while(true)
		{
			//将100张票全部卖出,并打印
			if(num > 0)
			{
				System.out.println(currentThread().getName()+"sale:"+num--);
			}
		}
	}
}


三:获取线程对象以及名称,实现Runnable接口

线程都有自己默认的名称:Thread-编号 该编号从0开始

currentThread():返回对当前正在执行的线程对象的引用

getName():获取线程名称

设置线程名称:setName()或者构造函数

Runnable接口:由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参数方法。

实现方式好处:避免了单继承的局限性

继承方式:线程代码存放于Thread子类run方法中

实现方法:线程代码存放于接口的子类run方法中

售票例子的实现方法:

class J11_2 
{
	public static void main(String[] args) 
	{
		Ticket k = new Ticket();
		Thread t1 = new Thread(k);
		Thread t2 = new Thread(k);
		Thread t3 = new Thread(k);
		Thread t4 = new Thread(k);

		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
class Ticket implements Runnable
{
	private int num = 50;
	Object obj = new Object();
	public void run()
	{
		while(true)
		{
			synchronized(obj)
			{
				if(num>0)
				{
					try
					{
						Thread.sleep(10);
					}
					catch (Exception e)
					{
					}
					System.out.println(Thread.currentThread().getName()+"sale:"+num--);		
				}
						
			}	
		}
	}
}


四:多线程的安全问题:

同步代码块:synchronized(对象){需要被同步的代码}

对象如同锁,持有锁的线程才可以在同步中运行。

同步的前提:

1,两个或两个以上的线程

2,必须是多个线程使用同一个锁

好处:解决了多线程的安全问题

弊端:多线程需要判断锁,较为耗费资源


同步函数:锁是this

静态同步函数:锁是class对象

(静态进内存时,内存中没有本类对象,但是一定会有该类对应的字节码文件对象。类名.class)


示例:用同步方法解决售票例子的安全隐患

class J11_4 
{
	public static void main(String[] args) 
	{
		Ticket k = new Ticket();
		Thread t1 = new Thread(k);
		Thread t2 = new Thread(k);
	//	Thread t3 = new Thread(k);
	//	Thread t4 = new Thread(k);

		t1.start();
		try
		{
			Thread.sleep(10);
		}
		catch (Exception e)
		{
		}
		k.flag = false;
		t2.start();
	//	t3.start();
	//	t4.start();
	}
}
class Ticket implements Runnable
{
	private static int num = 100;
	boolean flag = true;
	//Object obj = new Object();
	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(Ticket.class)
				{
					if(num>0)
					{
						try
						{
							Thread.sleep(10);
						}
						catch (Exception e)
						{
						}
						System.out.println(Thread.currentThread().getName()+" code "+"sale:"+num--);		
					}	
				}
				
			}
		}
		else

			while(true)
			{
				show();		
			}
	}
	static synchronized void show()
	{
		if(num>0)
		{
			try
			{
				Thread.sleep(10);
			}
			catch (Exception e)
			{
			}
			System.out.println(Thread.currentThread().getName()+" show "+"sale:"+num--);		
		}	
	}
}


五:单例设计模式,死锁

死锁:同步中嵌套同步

示例:用同步方法解决懒汉式中的安全隐患

//懒汉式
class Single
{
	private single(){}
	private static Single s = null;
	public static Single getInstance()
	{
		if(s==null)
		{
			synchronized (Single.class)
			{
				if(s==null)
					s = new Single();
			}
		}
		return s;
	}
}

六:线程间通信

背景:多个线程应在操作同一个资源,但操作的功能不同

JDK1.5中提供了多线程升级解决方案;

将同步synchronized替换成Lock操作;

将Object中的wait,notify,notifyAll替换成了Condition对象)

wait();notify();notifyAll():都是用在同步中,因为要对持有监视器(锁)的线程操作。

lock() 获取锁

unlock() 释放锁

newCondition():返回绑定到此Lock实例的新Condition实例

Condition接口:

await():造成当前线程在接到信号或被中断之前一直处于等待状态

signal():唤醒一个等待线程

signalAll():唤醒所有等待线程


输入输出线程通信示例:

class J12_1 
{
	public static void main(String[] args) 
	{
		Res r = new Res();
		Input i = new Input(r);
		Output o = new Output(r);
		Thread t1 = new Thread(i);
		Thread t2 = new Thread(o);

		t1.start();
		t2.start();
	}
}
class Res
{
	private String name;
	private String sex;
	private boolean flag = false;
	synchronized void set(String name,String sex)
	{
		if(flag)
			try{this.wait();}catch(Exception e){}
		this.name = name;
		this.sex = sex;
		flag = true;
		this.notify();
	}
	synchronized void out()
	{
		if(flag)
		{
			System.out.println(name+"..."+sex);
			flag =false;
			this.notify();
		}
		else
			try{this.wait();}catch(Exception e){}
		
	}
}
class Input implements Runnable
{
	private Res r;
	int i = 0;
	Input(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		while (true)
		{
			if(i==0)
			{
				r.set("Mack","Man");
			}
			else
			{
				r.set("莉莉","女");
			}
			i=++i%2;
		}
	}
}
class Output implements Runnable
{
	Res r;
	Output(Res r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.out();	
		}
		
	}
}

七:停止线程,守护线程,优先级

停止线程:

1,定义循环结束标志

2,使用interrupt方法(结束冻结状态,使线程回到运行状态中来)

setDeamon(boolean on):将该线程标记为守护线程或用户线程

当正在运行的线程都是守护线程时,Java虚拟机退出;

该方法必须在启动线程前启用)

join()等待该线程终止

(当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行)

toString()返回该线程的字符串表示形式。包括线程名称,优先级和线程组。

setPriority(int newPriority)更改线程的优先级

yeild()暂停当前正在执行的线程对象,并执行其他线程。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值