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");
}
}
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时间片的同时,同时释放锁标记。