------------ ASP.Net+Android+IOS开发、.Net培训、期待与您交流!-----------
多线程
1)概念
进程
是一个正在执行的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程
就是进程中的一个独立的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。
一个进程中至少有一个线程。
2)多线线程的实现
创建线程
1、继承thread
2、实现Runnable接口
两种方法区别:
1、实现Runnable接口避免了单继承的局限性
2、继承Thread类线程代码存放在Thread子类的run方法中
继承方式
/*
创建两线程,和主线程交替运行。
*/
//创建线程Test
class Test extends Thread
{
// private String name;
Test(String name)
{
super(name);
// this.name=name;
}
//复写run方法
public void run()
{
for(int x=0;x<60;x++)
System.out.println(Thread.currentThread().getName()+"..run..."+x);
// System.out.println(this.getName()+"..run..."+x);
}
}
class ThreadTest
{
public static void main(String[] args)
{
new Test("one+++").start();//开启一个线程
new Test("tow———").start();//开启第二线程
//主线程执行的代码
for(int x=0;x<170;x++)
System.out.println("Hello World!");
}
}
实现Runnable接口的方式
需求:简单的卖票程序。
多个窗口卖票。
*/
class Ticket implements Runnable//extends Thread
{
private int tick = 100;
public void run()
{
while(true)
{
if(tick>0)
{
//显示线程名及余票数
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
//创建Runnable接口子类的实例对象
Ticket t = new Ticket();
//有多个窗口在同时卖票,这里用四个线程表示
Thread t1 = new Thread(t);//创建了一个线程
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();//启动线程
t2.start();
t3.start();
t4.start();
}
}
3)线程状态
线程几种状态
新建状态:等待启动;
就绪状态:调用start启动线程,排队等候执行权
运行状态:具有执行资格和执行权。
临时状态(阻塞):有执行资格,但是没有执行权。
冻结状态:遇到sleep(time)方法和wait()方法时,失去执行资格和执行权,sleep方法时间到或者调用notify()方法时,获得执行资格,变为临时状态。
消忙状态:stop()方法,或者run方法结束
4)线程安全
原因: 有共享数据,共享数据被多条语句操作,是在多线程程序中
解决方案
同步代码块:synchronized(对象){被同步的代码}
同步函数:把synchronized加在方法上
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
同步代码块
/*
给卖票程序示例加上同步代码块。
*/
class Ticket implements Runnable
{
private int tick=100;
Object obj = new Object();
public void run()
{
while(true)
{
//给程序加同步,即锁
synchronized(obj)
{
if(tick>0)
{
try
{
//使用线程中的sleep方法,模拟线程出现的安全问题
//因为sleep方法有异常声明,所以这里要对其进行处理
Thread.sleep(10);
}
catch (Exception e)
{
}
//显示线程名及余票数
System.out.println(Thread.currentThread().getName()+"..tick="+tick--);
}
}
}
}
}
同步函数
class Ticket implements Runnable
{
private int tick=100;
Object obj = new Object();
public void run()
{
while(true)
{
show();
}
}
//直接在函数上用synchronized修饰即可实现同步
public synchronized void show()
{
if(tick>0)
{
try
{
//使用线程中的sleep方法,模拟线程出现的安全问题
//因为sleep方法有异常声明,所以这里要对其进行处理
Thread.sleep(10);
}
catch (Exception e)
{
}
//显示线程名及余票数
System.out.println(Thread.currentThread().getName()+"..tick="+tick--);
}
}
}
同步函数用使用的锁
函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this。
synchronized(this)
静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class
synchronized(Ticket.class)
加同步的单例设计模式 (面试常考)
懒汉式,(特点延迟加载,多线程访问会出现安全问题,
用同步代码块和同步函数可以解决这个问题,但有些低效,加双重判断提高效率
用到的锁是该类所属的字节文件对象)
/*
加同步的单例设计模式————懒汉式
*/
class Single
{
private static Single s = null;
private Single(){}
public static void getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}
5)死锁
同步嵌套同步,而锁却不同。
//a要b的锁,b要a的锁
class Test implements Runnable
{
private boolean flag=true;
Test(boolean flag){
this.flag=flag;
}
@Override
public void run() {
// TODO Auto-generated method stub
if(flag){
while(true){
synchronized (MyLock.locka) {
System.out.println("if---a");
synchronized (MyLock.lockb) {
System.out.println("if----b");
}
}
}
}
else{
while(true)
{
synchronized (MyLock.lockb) {
System.out.println("else``````b");
synchronized (MyLock.locka) {
System.out.println("else```````a");
}
}
}
}
}
}
class MyLock
{
static Object locka = new Object();
static Object lockb = new Object();
}
class Deadlock {
public static void main(String[] args) {
Thread t1=new Thread(new Test(true));
Thread t2=new Thread(new Test(false));
t1.start();
t2.start();
}
}
6)线程间的通信
*
生产者生产商品,供消费者使用
有两个或者多个生产者,生产一次就等待消费一次
有两个或者多个消费者,等待生产者生产一次就消费掉
*/
import java.util.concurrent.locks.*;
class Resource
{
private String name;
private int count=1;
private boolean flag = false;
//多态
private Lock lock=new ReentrantLock();
//创建两Condition对象,分别来控制等待或唤醒本方和对方线程
Condition condition_pro=lock.newCondition();
Condition condition_con=lock.newCondition();
//p1、p2共享此方法
public void setProducer(String name)throws InterruptedException
{
lock.lock();//锁
try
{
while(flag)//重复判断标识,确认是否生产
condition_pro.await();//本方等待
this.name=name+"......"+count++;//生产
System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产
flag=true;//控制生产\消费标识
condition_con.signal();//唤醒对方
}
finally
{
lock.unlock();//解锁,这个动作一定执行
}
}
//c1、c2共享此方法
public void getConsumer()throws InterruptedException
{
lock.lock();
try
{
while(!flag)//重复判断标识,确认是否可以消费
condition_con.await();
System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费
flag=false;//控制生产\消费标识
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
//生产者线程
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res=res;
}
//复写run方法
public void run()
{
while(true)
{
try
{
res.setProducer("商品");
}
catch (InterruptedException e)
{
}
}
}
}
//消费者线程
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res=res;
}
//复写run
public void run()
{
while(true)
{
try
{
res.getConsumer();
}
catch (InterruptedException e)
{
}
}
}
}
class ProducerConsumer
{
public static void main(String[] args)
{
Resource res=new Resource();
new Thread(new Producer(res)).start();//第一个生产线程 p1
new Thread(new Consumer(res)).start();//第一个消费线程 c1
new Thread(new Producer(res)).start();//第二个生产线程 p2
new Thread(new Consumer(res)).start();//第二个消费线程 c2
}
}
*
生产者生产商品,供消费者使用
有两个或者多个生产者,生产一次就等待消费一次
有两个或者多个消费者,等待生产者生产一次就消费掉
*/
import java.util.concurrent.locks.*;
class Resource
{
private String name;
private int count=1;
private boolean flag = false;
//多态
private Lock lock=new ReentrantLock();
//创建两Condition对象,分别来控制等待或唤醒本方和对方线程
Condition condition_pro=lock.newCondition();
Condition condition_con=lock.newCondition();
//p1、p2共享此方法
public void setProducer(String name)throws InterruptedException
{
lock.lock();//锁
try
{
while(flag)//重复判断标识,确认是否生产
condition_pro.await();//本方等待
this.name=name+"......"+count++;//生产
System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产
flag=true;//控制生产\消费标识
condition_con.signal();//唤醒对方
}
finally
{
lock.unlock();//解锁,这个动作一定执行
}
}
//c1、c2共享此方法
public void getConsumer()throws InterruptedException
{
lock.lock();
try
{
while(!flag)//重复判断标识,确认是否可以消费
condition_con.await();
System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费
flag=false;//控制生产\消费标识
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
//生产者线程
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res=res;
}
//复写run方法
public void run()
{
while(true)
{
try
{
res.setProducer("商品");
}
catch (InterruptedException e)
{
}
}
}
}
//消费者线程
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res=res;
}
//复写run
public void run()
{
while(true)
{
try
{
res.getConsumer();
}
catch (InterruptedException e)
{
}
}
}
}
class ProducerConsumer
{
public static void main(String[] args)
{
Resource res=new Resource();
new Thread(new Producer(res)).start();//第一个生产线程 p1
new Thread(new Consumer(res)).start();//第一个消费线程 c1
new Thread(new Producer(res)).start();//第二个生产线程 p2
new Thread(new Consumer(res)).start();//第二个消费线程 c2
}
}