一、进程
1、进程概念
进程是程序在处理机上的一次执行过程,是动态的。进程是一个具有一定独立功能的程序,一个实体,每个进程都有它自己的地址空间。
进程的状态:运行状态、就绪状态、阻塞状态。
二、线程
1、线程概念
一个进程可以划分为若干个线程,线程是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程。
并行:两个进程同时运行
并发:宏观同时,微观分时。
线程实现的两种方式:继承Thread类,实现Runnable接口
import sun.font.FontRunIterator;
public class Test01 {
public static void main(String[] args){
Mythread mt=new Mythread();
mt.start();//启动线程,虚拟机启动
MyRunnable mr=new MyRunnable();
Thread t=new Thread(mr);
t.start();
}
}
//实现线程的第一种方式
class Mythread extends Thread{
public void run(){
for (int i = 0; i < 50; i++) {
System.out.println("当前线程的名字:"+Thread.currentThread().getName()+" "+i);
}
}
}
//实现线程的第二种方式,推荐使用
class MyRunnable implements Runnable{
public void run(){
for (int i = 0; i < 50; i++) {
System.out.println("当前线程的名字:"+Thread.currentThread().getName()+" "+i);
}
}
}
2、线程休眠、join、中断
线程休眠可以释放CPU时间片。
MyRunnable mr=new MyRunnable();
Thread t=new Thread(mr);
t.setDaemon(true);//把线程设置为守护线程,线程分为守护线程和用户线程,当程序中没有用户线程时JVM会退出
t.start();
for (int i = 0; i < 50; i++) {
System.out.println("当前线程的名字:"+Thread.currentThread().getName()+" "+i);
/* try {
Thread.sleep(300);//线程休眠释放时间片
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}*/
if(i==20){
try {
t.join();//让t线程执行完毕再执行主线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3、线程同步
import java.util.concurrent.locks.ReentrantLock;
public class Test01 {
public static void main(String[] args) {
MyRunnable1 my1=new MyRunnable1();
Thread t1=new Thread(my1);
Thread t2=new Thread(my1);
t1.start();
t2.start();
}
}
//多线程共享数据时,产生线程不安全现象,比如两个窗口售票,一个票只能售出一次,解决多线程不安全,引入线程同步,会牺牲性能换取线程安全
//实现同步的三种方法:同步代码块,同步方法,lock
class MyRunnable1 implements Runnable{
private int ticket=10;
// private Object obj=new Object();
public void run(){
for (int i = 0; i < 300; i++) {
/*if (ticket > 0) {
synchronized (this) {//同步代码块,括号里是同步的对象,任意一个对象,相当于上锁
ticket--;
System.out.println("您购买的票剩余" + ticket + "张");
try {
Thread.sleep(1000);//不释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}*/
// method();//同步方法
method1();
}
}
//同步方法
private synchronized void method(){
if (ticket > 0) {
synchronized (this) {//同步代码块,括号里是同步的对象,任意一个对象,相当于上锁
ticket--;
System.out.println("您购买的票剩余" + ticket + "张");
try {
Thread.sleep(1000);//不释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//互斥锁
ReentrantLock lock=new ReentrantLock();
private void method1() {
lock.lock();//上锁
try {
if (ticket > 10) {
ticket--;
System.out.println("您购买的票剩余" + ticket + "张");
try {
Thread.sleep(1000);//不释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}finally {
lock.unlock();//解锁
}
}
}
同步准则:
(1)使代码块保持简短,不把随线程变化的预处理和后处理移出synchronized块。
(2)不要阻塞。
(3)在持有锁的时候,不要对其他对象调用同步方法。
4、线程死锁
多线程中要进行资源共享,就要进行同步,但同步过多会造成死锁。死锁一般在程序运行时才有可能出现。
5、线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Test02 {
public static void main(String[] args) {
//创建线程池
// ExecutorService es=Executors.newSingleThreadExecutor();//创建单线程
// ExecutorService es=Executors.newFixedThreadPool(3);//创建3个线程
//以上两种使用较多
// ExecutorService es=Executors.newCachedThreadPool();//创建一个可缓存的线程池,不会对线程池大小做限制
ScheduledExecutorService es= Executors.newScheduledThreadPool(3);//创建一个无限大小的线程池
// es.execute(new MyRunnable());//执行任务,使用单个线程执行
// es.execute(new MyRunnable());//多线程使用另一个线程执行
es.schedule(new MyRunnable(),1000, TimeUnit.MILLISECONDS);//延迟一秒执行
es.shutdown();//结束
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"-------"+i);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
三、生产者-消费者模型
public class Test01 {
public static void main(String[] args) {
Food f=new Food();
Producter p=new Producter(f);
Consumer c=new Consumer(f);
Thread t1=new Thread(p);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
}
class Producter implements Runnable{
private Food food;
public Producter(Food food) {
this.food = food;
}
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
food.set("可乐鸡翅","酸酸甜甜");
}else{
food.set("糖醋排骨","口感鲜美");
}
}
}
}
class Consumer implements Runnable{
private Food food;
public Consumer(Food food) {
this.food = food;
}
public void run() {
for (int i = 0; i < 20; i++) {
food.get();
}
}
}
class Food{
private String name;
private String special;
private boolean flag=true;//true表示生产,false表示消费
public Food(String name, String special) {
this.name = name;
this.special = special;
}
//生产的方法
public synchronized void set(String name,String special) {
if (!flag) {//不能生产
try {
this.wait();//线程进入等待状态,释放监视器的所有权(Object类的方法)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.setName(name);//可以生产
try {
Thread.sleep(500);//线程休眠,不释放监视器的所有权
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setSpecial(special);//生产结束
flag=false;//不能生产
this.notify();//唤醒线程
}
//消费的方法
public synchronized void get(){
if(flag){//不能消费
try {
this.wait(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {//可以消费
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName()+"---->"+this.getSpecial());//消费结束
flag=true;//不能消费
this.notify();//唤醒一个线程
// this.notifyAll();//唤醒所有线程
}
@Override
public String toString() {
return "Food{" +
"name='" + name + '\'' +
", special='" + special + '\'' +
'}';
}
public Food() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSpecial() {
return special;
}
public void setSpecial(String special) {
this.special = special;
}
}
sleep和wait的区别:
sleep:让线程休眠,让出CPU的时间片,但是不释放监视器的所有权(对象锁)。
wait:让线程进入等待状态,让出CPU的时间片,释放监视器的所有权(Object类的方法),等待其他线程通过notify方法来唤醒。