线程

来源:互联网 发布:免费数据分析软件 编辑:程序博客网 时间:2024/06/05 02:36
一、进程【理解】
1. 概念: 进程是指操作系统(OS)中并发执行的多个任务。
    2. 并发执行的原理:宏观并行,微观串行。
二、线程
1. 概念:线程是一个进程中并发执行的多个程序逻辑(任务);
             线程是进程的执行单位。(线程被称为轻量级进程) 【理解】
    2. 组成:
① CPU:获取OS分配的CPU时间片。
② 数据:堆空间共享,栈空间独立。
堆空间:存储对象,堆空间共享。
栈空间:存储局部变量,栈空间独立。
③ 代码:代码实现多线程【开发应用重点】
a. 第一种实现多线程
I. 继承Thread类,覆盖run方法
II. 创建线程对象:
MyThread t=new MyThread();
III. 开启线程:调用start()方法

t.start();//JVM会自动调用run方法

eg:

package demo20171115;
/*
 * 线程:一个进程中并发执行多个程序逻辑,线程是进程执行单元(多并发)
 * cpu每次只能执行一个应用程序,这时OS操作系统分配时间片,交替运行
 * 实现线程第一种方式
 */
public class TestThread {
public static void main(String[] args) {
MyThread myThread = new MyThread();           //创建线程
myThread.start();                             //开启线程,java虚拟机为默认调用run()方法
}
}
class MyThread extends Thread{                //继承Thread类
public void run(){                        //覆盖run()方法
System.out.println("666");
}
}

            b. 第二种实现多线程:
I. 实现Runnable接口,同时实现run方法
II. 创建目标对象:
MyTarget tg=new MyTarget();
III. 创建线程对象,同时将目标对象作为参数传递:
Thread t=new Thread(tg);
IV. 开启线程:调用start方法

t.start();

eg:

package demo20171115;
/**
 * 创建线程:实现Runnable接口
 * @author Mr fage
 * 2017-12-3下午3:48:17
 *
 */
public class TestRunnable {
public static void main(String[] args) throws Exception {
//创建目标对象
TT tt = new TT();
//创建线程对象,将目标对象作为参数
Thread thread = new Thread(tt);
//开启线程,JVM自动调用run();
thread.start();
//让当前线程睡眠(main())
Thread.sleep(5000);
System.out.println("777777");
}
}
class TT implements Runnable{
@Override
public void run() {
System.out.println("66666");
}
}

三、线程状态
1. 状态图详见pdf.【理解】
2. 常见方法:
① sleep(long ms):让当前线程处于休眠状态,单位是毫秒。
                   处于休眠状态的线程会让出CPU时间片,但是不释放锁标记。
   调用sleep方法的线程进入限期等待状态(Timed Waiting)。
join():加入,合并到自身线程任务中,优先执行。

   例如:main函数中调用t.join()//主线程让t线程优先执行。

四、线程同步【重点】
1. 临界资源:多线程并发时,多个线程共享的同一个对象。
    2. 原子操作:不可分割的多步操作,被视为一个整体,其顺序和步骤不允许被打破。
3. 线程同步:多线程并发时,为了保证临界资源的正确性,从而不破坏程序中
             原子操作。
4. 线程同步的方式:【开发应用重点】
① 同步代码块:对临界资源对象加锁
a. 位置:定义在方法内部
b. 语法: synchronized(临界资源){
              //原子操作...
          }
c. 线程必须获取临界资源的锁标记,才能执行同步代码块中{}的内容;
   而且{}中的内容全部执行完毕,才释放锁标记。
   如果线程没有获取临界资源的锁标记,则进入阻塞状态(Blocked状态),
   只有获取类锁标记,才能从阻塞状态出来,同时拥有CPU,才能执行{}中
   的内容。
② 同步方法:
   a. synchronized 修饰方法
   b. 修饰符 synchronized 返回值类型 方法名(形参){
  //原子操作...
      }   
  相当于:
synchronized(this){
//原子操作...

}

eg:

package demo20171117;
/*
 * 线程同步方法
 * 线程同步:
 * 多并发,为了保护临界资源的正确性,从而不破坏原子操作
 */
public class TestXianChengTongBuFangfa {
public static void main(String[] args) {
//创建临界资源
MyTest myTest = new MyTest();
MyThread5 myThread5 = new MyThread5(myTest);
myThread5.start();
MyThread6 myThread6 = new MyThread6(myTest);
myThread6.start();
myTest.DaYin();
}
}
//线程一
class MyThread5 extends Thread{
public MyTest myTest;
public MyThread5(){}
public MyThread5(MyTest myTest){
this.myTest=myTest;
}
//覆盖run方法
public void run(){
myTest.add("888");
}

}
//线程二 
class MyThread6 extends Thread{
public MyTest myTest;
public MyThread6(){}
public MyThread6(MyTest myTest){
this.myTest=myTest;
}
//覆盖run方法
public void run(){
myTest.add("668");
}
}
//定义一个类
class MyTest{
private String[] str ={"1","2","3","",""};
private int index=3;
public synchronized void add(String s){           //同步方法
str[index]=s;
index++;
}
public void DaYin(){
System.out.println("有效元素的个数:"+index);
for(int i=0;i<str.length;i++){
System.out.print(str[i]+"\t");

}
System.out.println();
}

}   

五、线程通信【了解】
1. wait():等待
       ① 位置:必须使用在该对象的同步代码块中。
   ② 作用:让当前线程处于等待状态
   ③ 注意:wait会让当前线程释放拥有的对象的锁标记,同时释放CPU.
2. notify()/notifyAll():通知
   ① notify:通知一个线程从等待状态出来;
      notifyAll:通知所有的线程从等待状态出来。
   ② 位置:必须使用在该对象操作的同步代码块中。
   ③ notify/notifyAll:只是通知的作用,不会让当前线程释放锁标记和CPU.

       面试重点: sleep(long ms)和wait()方法的区别?????

eg:

package demo20171119;
/**
 * 生产者和消费者
 * @author Mr fage
 * 2017-12-3下午4:51:31
 *
 */
public class TestProductAndConsumer {
public static void main(String[] args) {
MyStack ms = new MyStack();

//入栈:A B C D E
/*ms.push("A");
ms.push("B");
ms.push("C");
ms.push("D");
ms.push("E");*/
// ms.push("F");
Productor p = new Productor(ms);
p.start();

//出栈
/*ms.pop();//e
ms.pop();//D
ms.pop();//C
ms.pop();//B
ms.pop();//A
*/
Consumer c = new Consumer(ms);
c.start();
}
}


//线程任务:往栈结构中存储元素--》生产者
class Productor extends Thread{
private MyStack ms;
public Productor(){}
public Productor(MyStack ms){
this.ms=ms;
}
public void  run(){
for(char c='A';c<='Z';c++){
ms.push(c+"");
}
}
}
//线程任务:从栈结构中取出元素--》消费者
class Consumer extends Thread{
private MyStack ms;
public Consumer(){}
public Consumer(MyStack ms){
this.ms=ms;
}
public void run(){
for(int i=1;i<=26;i++){
ms.pop();
}
}
}
//栈结构:先进后出(FILO),后进先出
class MyStack{
private String[] str=new String[5];
private int index;//记录栈结构中的有效元素的个数
//入栈
public synchronized void push(String s){
while(index==str.length){                   //用while因为生产者和消费者多对多的关系
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
str[index]=s;
System.out.println(s+"入栈..."+index);
index++;
this.notifyAll();
}
//出栈
public synchronized void pop(){
while(index==0){          //??????
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
index--;
System.out.println(str[index]+"出栈...."+index);
str[index]=null;
this.notifyAll();
}
}


sleep():让当前线程休眠,释放CPU时间片,不释放锁标记。

wait():让当前线程等待,释放CPU时间片的同时,同时释放锁标记。

原创粉丝点击