Java多线程学习笔记

Java多线程学习笔记

1.线程的概念
    操作系统可以运行多个进程(Process),每一个进程又可以创建多个线程(Thread).
    操作系统启动一个程序时,先在系统中建立一个进程,接着在这个进程中至少建立一个线程(主线程)作为程序运行的入口点,线程是依附于进程而存在的,并且至少包含一个主线程。
    线程和进程一样,也有创建、销毁和切换等状态,但负荷远小于进程,称为轻量级进程.
    线程可以共享进程的内存,并且还有一个属于自己的内存空间(称为线程栈),是在建立线程时由系统分配的,主要用来保存线程内部使用的数据。

2.线程的状态
    (1)New(新建)
    (2)Runnable(可运行、就绪)
    (3)Running(运行)
    (4)Blocked(被阻塞、挂起)
    (5)Dead(死亡)

3.线程类Thread常用方法
    run()               线程运行时所执行的代码,子类必须通过覆盖该方法来实现自己的功能。
    start()             启动线程
    sleep(long milis)   休眠,时间单位毫秒
    interrupt()         中断线程
    interrupted()       判断当前线程是否被中断(会清除中断状态标记)
    isInterrupted()     判断指定线程是否被中断
    isAlive()           判断线程是否处于活动状态(已调用start,但run还未返回)
    currentThread()     返回当前线程对象的引用.
    setName(String threadName)   设置线程的名字
    getName()           获取线程的名字,返回线程的名字
    join([long milis[,int nanos]])   连接线程,加入线程,须等待加入的线程执行完
    destroy()           销毁线程
    yield()             暂停当前线程,让其他线程执行
    setPriority(int p)  设置线程的优先级
    notify()
    notifyAll()
    wait()

4.使用继承线程类Thread创建线程
    使用线程的注意点: 编写线程执行的方法(run()方法),启动线程(start()方法)
    线程类Thread是在包java.lang中定义的.
    示例:
public class ThreadTest1 extends Thread{
 String threadName;
 
 public ThreadTest1(String threadName){
  System.out.println("初始化线程:" + threadName);
  this.threadName = threadName;
  
 }
 
 //线程运行时执行的代码
 public void run(){
  for(int i=0; i<3; i++){
   System.out.println("正在运行线程" + threadName);
   try {
    Thread.sleep(3);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }   
  }
 }
 
 public static void main(String[] args){
  System.out.println("开始线程测试");
  ThreadTest1 thread1 = new ThreadTest1("线程1");
  ThreadTest1 thread2 = new ThreadTest1("线程2");
  ThreadTest1 thread3 = new ThreadTest1("线程3");
  
  thread1.start();  //启动线程
  thread2.start();  //启动线程  
  thread3.start();  //启动线程
  
  thread2.setPriority(MAX_PRIORITY); //设置线程优先级
  
  System.out.println("结束线程测试");
 }
}
运行结果:
开始线程测试
初始化线程:线程1
初始化线程:线程2
初始化线程:线程3
正在运行线程线程2
正在运行线程线程3
结束线程测试
正在运行线程线程1
正在运行线程线程3
正在运行线程线程2
正在运行线程线程1
正在运行线程线程2
正在运行线程线程1
正在运行线程线程3


5.实现Runnable接口来创建线程.
    接口Runnable在包java.lang中.
    示例:
class MySuper {
 protected String myName;
 
 public MySuper(String Name) {
  this.myName = Name;
  System.out.println("初始化对象:" + this.myName);
 }
 
}

class MySub extends MySuper implements Runnable {

 public MySub(String Name) {
  super(Name);
 }
 
 //线程运行时执行的代码,实现接口Runnable
 public void run() {
  
  for (int i=0; i<3; i++) {
   System.out.println("运行线程" + super.myName);
   try {
    Thread.sleep(3);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  
 }
}

public class ThreadTest2 {
 
 public static void main(String[] args) {
  System.out.println("开始线程测试");
  
  MySub myobject1 = new MySub("对象1");
  MySub myobject2 = new MySub("对象2");
  
  Thread thread1 = new Thread(myobject1);
  Thread thread2 = new Thread(myobject2);
  thread1.start();
  thread2.start();
  
  System.out.println("结束线程测试");
 }
}
运行结果:
开始线程测试
初始化对象:对象1
初始化对象:对象2
结束线程测试
运行线程对象2
运行线程对象1
运行线程对象2
运行线程对象1
运行线程对象1
运行线程对象2


6.线程同步
    进程的多个线程共享一个对象,当一个线程在更新该对象时,另一个线程也试图更新或读取该对象,将会破坏数据的一致性。需要使用线程同步来避免共享对象的访问冲突。实质是对共享资源加锁。
    方法同步
    public synchronized void methodName([parameterList]){
        //操作共享对象
    }

    对象同步
    public void mymethod(){
        synchronized(this){
            //操作共享对象
        }
    }   

7.死锁
    死锁是指线程间互相等待对方的资源,而不能继续执行的情况。
    当线程同步synchronized使用不当可能导致死锁。持有一个共享资源的锁并试图获取另一个时,有可能发生死锁。
    造成死锁问题的本质是对共享资源的无序使用造成的,在程序设计时需要理清访问资源的顺序,应确保每个线程获取资源的顺序相同,释放资源与获取资源的顺序相反。

8.线程通信
    在多线程应用中,有时线程之间需要互相交流和等待,实现互相通信。可以通过共享的数据做到线程互相交流,通过线程控制方法使线程相互等待。
    java.lang.Object提供wait()/notify()/notifyAll()三个方法协调线程间的运行进度,实现线程通信。
    线程通信建立在生产者和消费者模型之上,一个线程产生输出(相当于生产产品,产生一串数据流,该线程为生产者),另一个线程进行输入(相当于消费者,消耗数据,该线程为消费者),先有生产者生产,才能有消费者消费,生产者没生产之前,通知消费者等待,生产后通知消费者消费,消费者消费后再通知生产者生产,即等待通知机制(Wait/Notify)。
    当线程获得某个对象的锁之后,若该行程调用wait()方法,则会退出所占用的处理器,并打开该对象的锁,转为阻塞状态,并允许其他同步语句获得对象锁。当执行条件满足后,将调用notify()方法,唤醒这个处于阻塞的线程,转为可运行状态,并有机会获得该对象的锁。但是,如果一个线程调用wait()方法后进入对该共享对象的等待状态,应确保有一个独立的线程最终会调用notify()方法,以使等待共享对象的线程回到可运行状态。
    线程通信示例
class ProducerThread extends Thread{
 long data = 0;
 
 ProducerThread() {
  start();
 }
 
 public void run() {
  synchronized(this) {
   System.out.println("开始生产");
   
   for(int i=0; i<100; i++) {
    data += i;
   }
   
   System.out.println("生产完毕");
   notify();
  }
 }
 
 synchronized public long getData() {
  try {
   wait();
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  
  return data;
 }
}

public class ThreadTest3 {
 
 public static void main(String[] args) {
  ProducerThread pt = new ProducerThread(); //
  System.out.println("生产结果: data=" + pt.getData());
 }
 
}
运行结果:
开始生产
生产完毕
生产结果: data=4950

9.线程组(Thread Group)
    在创建线程之前,可以创建一个ThreadGroup对象,然后将创建的线程依次加入.
    ThreadGroup tg = new ThreadGroup("myThreadGroup");
    Thread myThread1 = new Thread(tg, "writer");
    Thread myThread2 = new Thread(tg, "reader");
    myThread1.start();
    myThread2.start();
    线程组的方法
    getName()          返回线程组的名字
    getParent()        返回线程的父线程组的名字
    activeCount()      返回组中当前
    setMaxPriority(int pri)    设置线程组中线程的最高优先级别
    getMaxPriority()           返回线程组中线程的最高优先级别
    interrupt()                中断
    resume()                   唤醒
    stop()                     停止
    suspend()                  挂起
    setDaemon(boolean daemon)  将线程组设置为守护状态(常驻内存)
    isDaemon()                 判断是否为守护线程组
    isDestroyed()              判断线程组是否已被销毁
    parentOf(ThreadGroup g)    判断线程组是否是线程组g或g的子线程组
   
10.生产者消费者应用示例
// 共享数据
class ShareData {
 public int data;  //共享数据,可以扩展为复杂的数据
}

// 共享数据控制
class DataControl {
 private ShareData Data;
 private boolean writeable = true;
 
 public synchronized void setShareData(ShareData data) {
  if (!writeable) {
   try {
    wait();  // wait()方法需要放在一个同步段里,否则出现异常java.lang.IllegalMonitorStateException:
   } catch (InterruptedException e) {
    // e.printStackTrace();
   }
  }
  
  this.Data = data; 
  writeable = false;  //标记已经生产,设为只读,准备消费
  notify();           //线程通信,通知消费者已经生产,可以消费
 }
 
 public synchronized ShareData getShareData() {
  if (writeable) {
   try {
    wait();
   } catch (InterruptedException e) {
    //e.printStackTrace();
   }
  }
  
  writeable = true; //标记已经消费,设为可写,准备生产
  notify();         //线程通信,通知生产者需要生产
  
  return this.Data;
 }
 
}

// 生产者线程
class Producer extends Thread {
 private DataControl dc;
 
 Producer(DataControl dc) {
  this.dc = dc;
 }
 
 public void run() {
  for (int i=1; i<=10; i++) {
   try {
    Thread.sleep((int) Math.random() * 100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   
   ShareData myData = new ShareData();
   myData.data = i;
   dc.setShareData(myData);
   System.out.println("生产者产生数据:" + myData.data);   
  }
 }
}

// 消费者线程
class Consumer extends Thread {
 private DataControl dc;
 
 Consumer(DataControl dc) {
  this.dc = dc;
 }
 
 public void run() {
  ShareData myData;
  
  do {
   try {
    Thread.sleep((int) Math.random() * 100);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   
   myData = dc.getShareData();
   System.out.println("消费者消费数据:" + myData.data);
   
  } while (myData.data <= 10);
 }
}

public class ThreadTest4 {

 public static void main(String[] args) {
  DataControl dc = new DataControl();
  new Consumer(dc).start();
  new Producer(dc).start();
 }
 
}
运行结果:
生产者产生数据:1
消费者消费数据:1
生产者产生数据:2
消费者消费数据:2
生产者产生数据:3
消费者消费数据:3
生产者产生数据:4
消费者消费数据:4
生产者产生数据:5
消费者消费数据:5
生产者产生数据:6
消费者消费数据:6
生产者产生数据:7
消费者消费数据:7
生产者产生数据:8
消费者消费数据:8
生产者产生数据:9
消费者消费数据:9
生产者产生数据:10
消费者消费数据:10

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值