Java多线程



1、 
线程的概念

现在的操作系统都是都任务的,在同一时刻允许运行多个程序。现在,人们都有单台拥

有多个CPU的计算机,俗称双核或者四核。但是并发执行的进程数目并不是由CPU数目决定的,操作系统将CPU的时间分配给每一个进程,给人一种并行出来的感觉。

多线程程序在较低层次上扩展了多任务的概念,一个程序执行多个任务。通常,每一个任务成为一个线程。能够同时运行一个以上线程的程序称为多线程程序。一个进程中至少有一个线程,在Java中这个线程运行代码存在与main方法中,该线程成为主线程。

多线程和多进程到底有哪些区别呢?本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使线程直间的通信比进程之间的通信更有效、更容易。此外,在有些操作系统中,与进程相比,线程更“轻量级”,创建、撤销一个线程比启动新进程的开销要小的多。

在实际应用中多线程非常有用。例如:一个浏览器可以同时下载多幅图片。

2、  定义线程

Java中已经定义好了一个Thread类。创建线程呢有两种方法,一种方法是将类声明为

Thread的子类。该子类应重写Thread类的run方法。

      定义线程的步骤:

1、 定义一个类并继承Thread类。

2、 复写Thread类中的run()方法。

3、 调用线程的start()方法;

示例如下:

 

class Thr extends Thread 
{
	public void run()
	{
		for(int i=0;i<100;i++)
		{
			System.out.println("Thr run");
		}
	
	}
}
class ThreadDemo
{
	public static void main(String[] arge)
	{
		Thr a = new Thr();
		a.start();
		for(int i=0;i<100;i++)
		{
			System.out.println("Hello Java");
		}
	}
}


为什么要覆盖run方法呢?

      Thread类用于描述一个线程,该类就定义一个功能,用于存储线程要运行的代码,该存储功能就是run方法。

      线程被创建之后有下述四种基本状态执行状态、就绪状态、阻塞状态、消亡状态。运行状态是程序表示线程正在获得处理机而运行;就绪状态是指线程已具备各种执行条件,一旦获得CPU就可以执行的状态;阻塞状态是指线程在执行中因某事件而受阻,比如掉用了Sleep()wait(),处于暂停执行状态。消亡状态是指线程结束不再被运行比如调用stop();

      线程的名字:每个线程有自己默认的名字,但是我们也可以自定义线程名字。默认的名字为直接调用getName()方法,名称为Thread-编号,编号从0开始。自定义名字为在Thread类中有一个构造方法为Thread(String name)方法,我们可以在继承时调用这个父类方法如下:

      class Thr extends Thread

{

             public Thr(Stringname)

             {

                    super(name);

             }

}

创建线程的另一种方法是声明实现Runnable接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。1、定义类并实现Runnable接口。2、覆盖Runnable接口中的run()方法。3、通过Thread类建立线程对象。4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。5、调用Thread类的start()方法开启线程并调用Runnable接口的run()方法。

示例如下:

class Ticket implements Runnable//创建Ticket类并实现Runnable接口
{
	public static int ticket = 100;
	public void run()//实现Runnable接口的run()方法
	{
		while(true)
		{
			if(ticket>0)
			System.out.println(Thread.currentThread().getName()+"~~~~~~"+ticket--);
		}
	}
}
class TicketDemo
{
	public static void main(String[] arge)
	{
		
		Ticket t = new Ticket();//创建Ticket类对象
		Thread a1 = new Thread(t);//将Ticket类对象作为参数传入Thread类对象
		Thread a2 = new Thread(t);
		a1.start();
		a2.start();
	}
}

为什么有了Thread类来创建线程还要有Runnable接口来创建线程呢?

在我们创建线程时是继承Thread类并复写run()方法,但是如果我们有一个需要进行多线程的运行的类,但是这个类已经继承过其他类,那么就不能再继承Thread类了,这个时候Runnable的优势就体现出来了,所以这个时候就要用到Runnable接口来实现。

3、多线程的安全问题

      问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行一部分,还没执行完,另一条线程参与进来执行,导致共享数据的错误。

      解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他的线程不可以参与执行。

      Java对于多线程的安全问题提供了专业的解决方式。同步代码块。

Synchronized(对象)

{

      需要被同步的代码;

}

      对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程即使获取CPU的执行权,也不能执行,因为锁还未被持有的线程释放。那究竟什么时候需要同步代码呢?

1、 必须要有两个以上或者两个以上的线程。

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

那么如何查找代码是否有安全问题呢?

1、 明确哪些代码是多线程运行代码。

2、 明确共享数据。

3、 明确多线程运行代码中哪些语句是操作共享数据的。

4、死锁

所谓死锁是指多个线程在运行过程中因争夺资源而造成的一种僵局,当线程在出于这种

僵局状态时,若无外力作用,它们将无法再向前推进。示例:


class Test implements Runnable
{
	private boolean flag;
	public Test(boolean flag)
	{
		this.flag = flag;
	}
	public void run()
	{
		if(flag)
		{
			synchronized(MyLock.locka)
			{
				System.out.println("if locka");
				synchronized(MyLock.lockb)
				{
					System.out.println("if lockb");
				}
			}
		}
		else
		{
			synchronized(MyLock.lockb)
			{
				System.out.println("else lockb");
				synchronized(MyLock.locka)
				{
					System.out.println("else locka");
				}
			}
		}
	}
}
class MyLock
{
	static Object locka = new Object();
	static Object lockb = new Object();
}
class DeathLockTest
{
	public static void main(String[] arge)
	{
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}


      这个程序将很有可能发生死锁。

5、线程间的通信

线程间的通信就是多个线程在操作同一个资源但是操作的动作不同。下面提供一个生产者和消费者的示例里面涉及Lock.lock()Lock.unlock()conditions.await()condition.signal()、的用法,示例如下:

import java.util.concurrent.locks.*;

class Resource//创建一个资源类
{
	private String name;
	private int count = 1;
	private boolean flag = false;
	private Lock lock = new ReentrantLock();
	private Condition condition_pro = lock.newCondition();
	private Condition condition_con = lock.newCondition();
	
	
	public void set(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	();
		}	
	}
	public void out()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;
	}
	public void run()
	{
		while(true)
		{
			try
			{
				res.set("商品");
			}
			catch(InterruptedException e)
			{
				
			}
			
		}
	}
}
class Consumer implements Runnable//建立一个消费者
{
	private Resource res;
	Consumer(Resource res)
	{
		this.res = res;
	}
	public void run()
	{
		while(true)
		{
			try
			{
				res.out();
			}
			catch(InterruptedException e)
			{
				
			}
			
		}
	}
}
class ProducerConsumerDemo2
{
	public static void main(String[] arge)
	{
		Resource r = new Resource();
		
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);
		
		Thread t1 = new Thread(pro);
		Thread t3 = new Thread(pro);
		Thread t2 = new Thread(con);
		Thread t4 = new Thread(con);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		
	}
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值