Java-线程详解

1、进程的概念:
进程是指运行中的程序,它是一个动态的概念,每个进程都有独立的内存空间。进程可以理解成运行中的程序。
2、线程的概念:
线程是进程的一个实体,是被系统独立调度和分配的基本单位。
3、多线程的概念:
多线程是指在同一个程序中,可以同时运行多个不同的线程执行不同的任务。
4、多线程的特点:
(1)一个进程包括多个线程。
(2)一个程序实现多个代码同时交替运行就需要产生多个线程。
(3)线程本身不拥有系统资源,与同属一个进程的其他线程共享所在进程所拥有的资源
(4)同一个进程中的多个线程之间可以并发执行。CPU会随机抽出时间,让我们的程序一会做这件事情,一会做另外一件事情。
5、多线程的目的就是最大限度的利用cpu资源。
6、线程模型:
(1)通过继承Thread类创建线程。普通java类如果继承Thread类,就称为一个线程类。并可以通过该类的start方法来启动线程,执行线程代码,线程代码写在重写的run方法中。
(2)通过实现Runnable接口创建线程。实现Runnable接口的类必须借助Thread类才能创建线程。通过Runnable接口创建线程分为两步:首先创建实现Runnable接口的类的实例。然后创建一个Thread类的对象,将实现接口类的实例作为参数传递给Thread类的构造方法中。最后通过Thread类的start方法启动线程。
7、线程的声明周期:新建、就绪、运行、阻塞、死亡
(1)新建状态(new Thread)
在java中,使用new操作符创建一个线程后,该线程仅仅是一个空对象,它具备了线程的一些特征,但此时系统并没有为其分配资源,这时线程处于创建状态。此时可以设置线程的一些属性,如优先级:setPriority  线程名setName  线程类型setDaemon 等
(2)就绪状态(Runnable)也称可运行状态
使用start方法启动一个线程之后,系统为该线程分配了处CPU外的所需资源,使该线程处于就绪状态。此外如果某个线程执行了yield方法,那么该线程会暂时被剥夺CPU资源,重新进入就绪状态。
(3)运行状态(Running)
Java运行系统通过调用选中一个处于就绪状态的线程,使其占有CPU并转为运行状态,此时系统真正执行线程中的run方法。可通过Thread类中的isAlive方法来判断线程是否处于就绪/运行状态,如果是的话返回True,当不是的话,返回false。此时可能线程处于阻塞状态,也可能处于停止状态。
(4)阻塞状态(Blocked)
一个正在运行的线程因某些原因不能继续运行时,就进入阻塞状态。这些原因包括:
a、当执行了某个线程对象的sleep等阻塞类型的方法时,该线程对象会被置入一个阻塞集(Blocked Pool)内,等待超时而自动苏醒。
b、当多个线程师徒计入某个同步区域时,没能进入该同步区域的线程会被置入锁定集(Lock Pool)内,直到获得该同步区域的锁,进入就绪状态。
c、当线程执行了某个对象的wait方法时,线程会被置入该对象的等待集(Wait Pool)中,直到执行了该对象的notify方法,wait/notify的方法执行要求线程首先获得给对象的锁。
(5)死亡状态(Dead)
线程在run方法执行结束后会进入死亡状态,此外,如果线程执行了interrupt或stop方法,那么它也会以异常退出方式进入死亡状态。
终止线程的三种方法:
第一 使用退出标志,也就是当run方法完成后终止,推荐使用。
第二 使用stop方法,不推荐。
第三 使用interrupt方法中断线程。
8、线程同步
线程同步是为了防止多个线程访问一个数据对象时,对数据造成破坏。
实现同步:首先将要竞争的资源私有化private。然后同步那些访问资源的代码,添加synchronized关键字。如果是同步某个方法,直接加关键字synchronized,如果是同步代码块加synchronized(this)。this代表当前类的对象,当然不一定非要当前对象,任意对象都可以,因为每个对象都有一把锁。
代码演示一:线程同步实现多窗口卖票
public class ThreadDemo3 {
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t = new Thread(st, "窗口一");
Thread t1 = new Thread(st, "窗口二");
t.start();
t1.start();
}
}
class SellTicket implements Runnable {
private int ticket = 10;
@Override
public void run() {
// 售票的代码
while (true) {
synchronized (this) {
notify();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "出售第" + ticket + "张票");
ticket--;
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}

}
}

}
代码示例二:线程同步实现窗口和ATM机取款
public class BankThreadDemo {
public static void main(String[] args) {
Bank bank=new Bank();
BankThread bt1= new BankThread(bank,"柜台");
bt1.start();
BankThread bt2= new BankThread(bank,"ATM");
bt2.start();
}
}
class BankThread extends Thread{
private Bank bank=null;
public BankThread(Bank bank,String name){
super(name);
this.bank=bank;
}
@Override
public void run() {
bank.getMoney(400);
}
}
class Bank{
private int account=500;
public synchronized void getMoney(int money){
if(money<0){
System.out.println(Thread.currentThread().getName()+"输入金额有误!");
}else if(account<0){
System.out.println(Thread.currentThread().getName()+"账号余额为零");
}else if(money>account){
System.out.println(Thread.currentThread().getName()+"账号余额不足!");
}else{
System.out.println(Thread.currentThread().getName()+"取款金额为:"+money);
account-=money;
System.out.println("账号余额为"+account);
}
}
}
释放锁:1.把同步的代码执行完毕,正常退出。2、持锁线程,在同步块内出现异常。3、持锁线程执行了wait方法也会释放锁。
死锁:一个线程拥有对象一的锁,同时又想获得对象二的锁。而此时另外一个线程拥有对象二的锁,同时又想获得对象一的锁,这样两个线程互相等待,就造成了死锁。为了避免死锁,尽量不要在同步代码块里面套用同步代码块。(其实对死锁形象的比喻就是黄宏演的那个开锁的小品一样)。
死锁代码演示:
public class DeadLockDemo {

public static void main(String[] args) {
DeadLock dl=new DeadLock();
DeadLockThread1 dt1=new DeadLockThread1(dl);
dt1.start();
DeadLockThread2 dt2=new DeadLockThread2(dl);
dt2.start();
}
}
class DeadLockThread1 extends Thread{
private DeadLock dl=null;
public DeadLockThread1(DeadLock dl){
this.dl=dl;
}
@Override
public void run() {
dl.method1();
}
}
class DeadLockThread2 extends Thread{
private DeadLock dl=null;
public DeadLockThread2(DeadLock dl){
this.dl=dl;
}
@Override
public void run() {
dl.method2();
}
}
class DeadLock{
Object o1=new Object();
Object o2=new Object();
public void method1() {
synchronized(o1){
System.out.println("先开箱子,给我拿身份证!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(o2){
System.out.println("开箱子拿到身份证!");
}
}
}
public void method2(){
synchronized (o2){
System.out.println("先给我身份证,再开箱子!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(o1){
System.out.println("有身份证了开箱子!");
}
}
}
}
9、线程通信
最典型的一个案例:生产者和消费者共享同一资源。仓库中只能存放一件物品,消费者消费掉之后,生产者才能放入产品,否则等待。同样只有仓库中有产品,消费者才能消费,否则等待。
代码演示:以生产和消费五个苹果为例
import java.util.LinkedList;
public class AppleDemo {
public static void main(String[] args) {
WareHouse wh=new WareHouse();
ProduceThread pt=new ProduceThread(wh);
pt.start();
EatThread et=new EatThread(wh);
et.start();
}
}
class ProduceThread extends Thread{
WareHouse wh=null;
public ProduceThread(WareHouse wh){
this.wh=wh;
}
@Override
public void run() {
wh.produceApple();
}
}
class EatThread extends Thread{
WareHouse wh=null;
public EatThread(WareHouse wh){
this.wh=wh;
}
@Override
public void run() {
wh.eatApple();
}
}
class WareHouse {
LinkedList<Apple> list = new LinkedList<Apple>();
public synchronized void produceApple() {
for (int i = 0; i < 20; i++) {
Apple apple = new Apple(i + 1);
produce(apple);
}
}
public synchronized void eatApple() {
for (int i = 0; i < 20; i++) {
eat();
}
}
private void produce(Apple apple) {
if (list.size() == 5) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list.addFirst(apple);
System.out.println("生产:" + apple);
notify();
}
private void eat() {
if (list.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Apple apple = list.removeFirst();
System.out.println("消费掉:" + apple);
notify();
}
}
class Apple {
private int id;
public Apple(int id) {
super();
this.id = id;
}
@Override
public String toString() {
return "苹果" + id;
}
}

猜你喜欢

转载自fengwuhen1990.iteye.com/blog/2342085