进程:正在运行的程序,是系统进行资源分配的基本单位。
线程,又称轻量级进程(Light Weight Process)。进程中的一条执行路径,也是CPU的基本调度单位。
进程与线程的区别:
线程的组成:
任何一个线程都具有基本的组成部分:
CPU时间片:操作系统(0S)会为每个线程分配执行时间。
运行数据:
堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。
栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈。
线程的逻辑代码。
线程的特点:
1、【继承Thread类,重写run方法】
2、【实现Runnable接口】
3、【实现Callable接口】
//获取线程ID和线程名称:
1、在Thread的子类中调用this.getId()或this.getName ()
2、使用Thread.currentThread().getId()和Thread. currentThread().getName ()
//修改线程名称,线程ID不能修改
1、调用线程对象的setName()方法。
2、使用线程子类的构造方法赋值。
/**
* 线程类
*/
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);//把name传给父类Thread的构造函数
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
// 方法1:this.getId()或this.getName ()
// this.getID:获取线程ID
// this.getName:获取线程名称
// System.out.println("线程ID:"+this.getId()+"线程名称:" +this.getName()+
// "子线程.........."+i);
// 方法2:Thread.currentThread():获取当前线程
System.out.println("线程ID:"+ Thread.currentThread().getId() +
"线程名称:"+Thread.currentThread().getName()+"子线程.........."+i);
}
}
}
public class Test {
public static void main(String[] args) {
//1.创建线程对象
MyThread myThread=new MyThread();
//2.启动线程,不能调用run()方法,在main()方法中调用run()方法相当于调用对象的一个普通方法
myThread.setName("我的子线程1");//修改线程名字,要在线程启动之前修改,线程ID不能修改
myThread.start();
MyThread myThread1=new MyThread("我的子线程2");
// myThread.setName("我的子线程2");
myThread1.start();
for (int i = 0; i < 500; i++) {
System.out.println("主线程========="+i);
}
}
}
实现四个窗口各卖100张票的功能:
/**
* 买票窗口类
*/
public class TicketWin extends Thread{
private int count=100;
public TicketWin() {
}
public TicketWin(String name) {
super(name);
}
@Override
public void run() {
//实现卖票功能
while (true){
if(count<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+count+"张票");
count--;
}
}
}
//测试类
public class TestWin {
public static void main(String[] args) {
//创建四个线程对象
TicketWin tw1=new TicketWin("1号窗口");
TicketWin tw2=new TicketWin("2号窗口");
TicketWin tw3=new TicketWin("3号窗口");
TicketWin tw4=new TicketWin("4号窗口");
//启动线程
tw1.start();
tw2.start();
tw3.start();
tw4.start();
}
}
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"........"+i);
}
}
}
//测试类
public class TestMyRunnable {
public static void main(String[] args) {
// //创建MyRunnable接口,表示线程要执行的功能
// MyRunnable mr=new MyRunnable();
// Thread thread=new Thread(mr,"我的线程1");
// thread.start();
// for (int i = 0; i < 500; i++) {
// System.out.println("main..........."+i);
// }
//只是用MyRunnable一次的话,代码有些冗长,使用匿名内部类进行优化
Thread thread=new Thread(new Runnable(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"........"+i);
}
}
},"我的线程1");
thread.start();
for (int i = 0; i < 500; i++) {
System.out.println("main..........."+i);
}
}
}
实现四个窗口一共卖100张票的功能:
/**
* 票类(共享资源类)
*/
public class TicketWin2 implements Runnable{
public int ticket=100;
@Override
public void run() {
while (true){
if (ticket<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
ticket--;
}
}
}
//测试类
public class TestWin2 {
public static void main(String[] args) {
TicketWin2 tw1=new TicketWin2();
Thread thread1=new Thread(tw1,"1号窗口");
Thread thread2=new Thread(tw1,"2号窗口");
Thread thread3=new Thread(tw1,"3号窗口");
Thread thread4=new Thread(tw1,"4号窗口");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
//这样执行会出现线程安全问题
你和你女朋友共用一张银行卡,你向卡中存钱,你女朋友从卡中取钱,使用程序模拟过程:
/**
* 银行卡类
*/
public class BankCard {
private double money;
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
//存钱
public class AddMoney implements Runnable{
private BankCard card;
public AddMoney() {
}
public AddMoney(BankCard card) {
this.card = card;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
card.setMoney(card.getMoney()+1000);
System.out.println(Thread.currentThread().getName()+"存了1000,余额是:"+card.getMoney());
}
}
}
//取钱
public class SubMoney implements Runnable{
private BankCard card;
public SubMoney() {
}
public SubMoney(BankCard card) {
this.card = card;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (card.getMoney()>=1000) {
card.setMoney(card.getMoney() - 1000);
System.out.println(Thread.currentThread().getName() + "取了1000,余额是:" + card.getMoney());
}else{
System.out.println("余额不足");
i--;
}
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
//1.创建一张银行卡
BankCard bankCard=new BankCard();
//2.创建存钱,取钱
AddMoney add=new AddMoney(bankCard);//可以使用匿名内部类简化代码
SubMoney sub=new SubMoney(bankCard);
//3.创建线程
Thread thread1=new Thread(add,"晨晨");//new Thread(add,"晨晨").start()
Thread thread2=new Thread(sub,"冰冰");
//4.启动线程
thread1.start();
thread2.start();
}
}
注:JDK1.5之后,就绪和运行统称为Runnable
//休眠: 当前线程主动休眠millis毫秒。
public static void sleep(long millis)
//放弃:当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。
public static void yield()
//加入:允许其他线程加入到当前线程中。
public final void join()
//修改线程优先级:
//线程对象.setPriority();线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多。
//守护线程:
//线程对象.setDaemon(true);设置为守护线程。
//线程有两类:用户线程(前台线程)、守护线程(后台线程)。
//如果程序中所有前台线程都执行完毕了,后台线程会自动结束。
//垃圾回收器线程属于守护线程。
//休眠
public class SleepThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"......"+i);
try {
Thread.sleep(1000);//休眠1000ms
//这个异常不能抛出,因为这个父类没有抛出异常
// 子类继承父类,子类不能抛出比父类更多更宽的异常
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//测试类
public class TestSleep {
public static void main(String[] args) {
SleepThread sleepThread=new SleepThread();
sleepThread.start();
SleepThread sleepThread1=new SleepThread();
sleepThread1.start();
}
}
//放弃
public class YieldThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"......"+i);
//主动放弃CPU
Thread.yield();
}
}
}
//测试类
public class TestYield {
public static void main(String[] args) {
YieldThread yieldThread=new YieldThread();
YieldThread yieldThread1=new YieldThread();
yieldThread.start();
yieldThread1.start();
}
}
//加入线程
public class JoinThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName()+"........"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//测试类
public class TestJoin {
public static void main(String[] args) {
JoinThread jt=new JoinThread();
jt.start();
try {
jt.join();//加入当前线程(main主线程),并阻塞当前线程,直到加入线程执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"=========="+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//修改线程优先级
public class PriorityThread extends Thread{
@Override
public void run(){
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"........"+i);
}
}
}
//测试类
public class TestPriority {
public static void main(String[] args) {
PriorityThread pt1=new PriorityThread();
PriorityThread pt2=new PriorityThread();
PriorityThread pt3=new PriorityThread();
pt1.setPriority(1);
pt3.setPriority(10);
pt1.start();
pt2.start();
pt3.start();
}
}
//守护线程
public class DaemonThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"........"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//测试类
public class TestDaemon {
public static void main(String[] args) {
//1.创建线程(默认是前台线程)
//主线程也属于前台线程
DaemonThread d1=new DaemonThread();
//设置线程为守护线程(后台线程)
//前台线程执行完毕,后台线程自动结束
d1.setDaemon(true);
d1.start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"=========="+i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 线程安全问题示例代码
* 两个线程同时向一个数组中存放数据
*/
public class ThreadSafe {
private static int index=0;
public static void main(String[] args) throws Exception{
//创建数组
String[] s=new String[5];
//创建两个操作
Runnable runnableA=new Runnable() {
@Override
public void run() {
s[index]="hello";
index++;
}
};
Runnable runnableB=new Runnable() {
@Override
public void run() {
s[index]="world";
index++;
}
};
//创建两个线程对象
Thread t1=new Thread(runnableA,"A");
Thread t2=new Thread(runnableB,"B");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(Arrays.toString(s));
}
}
//执行结果
//[world, null, null, null, null]
//同步代码块
synchronized(临界资源对象){//对临界资源对象加锁
//代码(原子操作)
}
//注:
//每个对象都有一个互斥锁标记,用来分配给线程的。
//只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块。
//线程退出同步代码块时,会释放相应的互斥锁标记。
/**
* 线程安全问题
* 两个线程同时向一个数组中存放数据
*/
public class ThreadSafe {
private static int index=0;
public static void main(String[] args) throws Exception{
//创建数组
String[] s=new String[5];
//创建两个操作
Runnable runnableA=new Runnable() {
@Override
public void run() {
synchronized (s){
s[index]="hello";
index++;
}
}
};
Runnable runnableB=new Runnable() {
@Override
public void run() {
synchronized (s){
s[index]="world";
index++;
}
}
};
//创建两个线程对象
Thread t1=new Thread(runnableA,"A");
Thread t2=new Thread(runnableB,"B");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(Arrays.toString(s));
}
}
//执行结果一定可以把hello和world写入数组,先后顺序不一定
//使用同步代码块来优化:四个窗口一共卖100张票
/**
* 票类(共享资源类)
*/
public class TicketWin2 implements Runnable{
public int ticket=100;
//创建锁
private Object obj=new Object();
@Override
public void run() {
while (true){
synchronized (obj){//不可以使用synchronized (new Object),因为在main进程中创建了四个进程,相当于创建了四把锁
//可以使用synchronized (this),可以使用当前对象作为锁
if (ticket<=0){
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
ticket--;
}
}
}
}
//测试类
public class TestWin2 {
public static void main(String[] args) {
TicketWin2 tw1=new TicketWin2();
Thread thread1=new Thread(tw1,"1号窗口");
Thread thread2=new Thread(tw1,"2号窗口");
Thread thread3=new Thread(tw1,"3号窗口");
Thread thread4=new Thread(tw1,"4号窗口");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
//使用同步代码块来优化:你和你女朋友共用一张银行卡,你向卡中存钱,你女朋友从卡中取钱,使用程序模拟过程:
/**
* 银行卡类
*/
public class BankCard {
private double money;
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
//存钱
public class AddMoney implements Runnable{
private BankCard card;
public AddMoney() {
}
public AddMoney(BankCard card) {
this.card = card;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (card) {
card.setMoney(card.getMoney() + 1000);
System.out.println(Thread.currentThread().getName() + "存了1000,余额是:" + card.getMoney());
}
}
}
}
//取钱
public class SubMoney implements Runnable{
private BankCard card;
public SubMoney() {
}
public SubMoney(BankCard card) {
this.card = card;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (card){
if (card.getMoney()>=1000) {
card.setMoney(card.getMoney() - 1000);
System.out.println(Thread.currentThread().getName() + "取了1000,余额是:" + card.getMoney());
}else {
System.out.println("余额不足");
i--;
}
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
//1.创建一张银行卡
BankCard bankCard=new BankCard();
//2.创建存钱,取钱
AddMoney add=new AddMoney(bankCard);//可以使用匿名内部类简化代码
SubMoney sub=new SubMoney(bankCard);
//3.创建线程
Thread thread1=new Thread(add,"晨晨");//new Thread(add,"晨晨").start()
Thread thread2=new Thread(sub,"冰冰");
//4.启动线程
thread1.start();
thread2.start();
}
}
synchronized 返回值类型 方法名称 (形参列表){//对当前对象(this)加锁
//代码(原子操作)
}
注:只有拥有对象互斥锁标记的线程,才能进入该对象加锁的同步方法中。
线程退出同步方法时,会释放相应的互斥锁标记。
//以四个窗口共卖100张票为例
/**
* 票类(共享资源类)
*/
public class TicketWin2 implements Runnable{
public int ticket=100;
//创建锁
private Object obj=new Object();
@Override
public void run() {
while (true){
if(!sale()){
break;
}
}
}
}
//同步方法:
public synchronized boolean sale(){//锁是当前对象,this
// public synchronized static boolean sale(){//锁是当前类,Ticket.class
if (ticket<=0){
return false;
}
System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
ticket--;
return true;
}
}
//测试类
public class TestWin2 {
public static void main(String[] args) {
TicketWin2 tw1=new TicketWin2();
Thread thread1=new Thread(tw1,"1号窗口");
Thread thread2=new Thread(tw1,"2号窗口");
Thread thread3=new Thread(tw1,"3号窗口");
Thread thread4=new Thread(tw1,"4号窗口");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
死锁;
/**
* 创建两个锁对象
*/
public class MyLock {
//两个锁
public static Object a=new Object();
public static Object b=new Object();
}
//男孩线程
public class Boy extends Thread{
@Override
public void run() {
synchronized (MyLock.a){
System.out.println("男孩拿到了a");
synchronized (MyLock.b){
System.out.println("男孩可以吃东西了");
}
}
}
}
//女孩线程
public class Girl extends Thread{
@Override
public void run() {
synchronized (MyLock.b){
System.out.println("女孩拿到了b");
synchronized (MyLock.a){
System.out.println("女孩可以吃东西了");
}
}
}
}
//测试类
public class TestDeadLock {
public static void main(String[] args) {
Boy boy=new Boy();
Girl girl=new Girl();
boy.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
girl.start();
}
}
public final void wait ()
public final void wait(long timeout)
//必须在对obj加锁的同步代码块中。在一个线程中,调用obj.wait() 时,此线程会释放其圳有的所有锁标记。同时此线程阻塞在o的等待队列中。释放锁,进入等待队列。
public final void notify()//随机唤醒一个在等待队列中的线程
public final void notifyAll() //随机所有在等待队列中的线程
//银行卡类
public class BankCard {
//余额
private double money;
private boolean flag=false;//true表示有钱,可以取钱;false表示没钱,可以存钱
//存钱
public synchronized void sava(double m){
while (flag){//有钱
try {
this.wait();//进入等待队列,同时释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
money=money+m;
System.out.println(Thread.currentThread().getName()+"存了"+m+"余额是"+money);
//修改标记
flag=true;
//唤醒存钱线程
this.notifyAll();
}
//取钱
public synchronized void take(double m){
while (!flag){//if(!flag):只判断一次
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
money=money-m;
System.out.println(Thread.currentThread().getName()+"取了"+m+"余额是"+money);
//修改标记
flag=false;
//唤醒取钱线程
this.notifyAll();//this.notify():只唤醒一个,多线程执行会出现死锁
}
}
//存钱操作
public class AddMoney implements Runnable{
private BankCard card=new BankCard();
public AddMoney(BankCard card) {
this.card = card;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
card.sava(1000);
}
}
}
//取钱操作
public class SubMoney implements Runnable{
private BankCard card=new BankCard();
public SubMoney(BankCard card) {
this.card = card;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
card.take(1000);
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
//1.创建银行卡
BankCard card=new BankCard();
//2.创建操作
AddMoney add=new AddMoney(card);
SubMoney sub=new SubMoney(card);
//3.创建线程对象
Thread chenchen=new Thread(add,"晨晨");
Thread bingbing=new Thread(sub,"冰冰");
Thread mingming=new Thread(add,"明明");
Thread lili=new Thread(sub,"丽丽");
//4.启动线程
chenchen.start();
bingbing.start();
mingming.start();
lili.start();
}
}
生产者、消费者问题:
若干个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个能存储多个产品的缓冲区,生产者将生产的产品放入缓冲区中,消费者从缓冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个满的缓冲区中放入产品。
//面包类
public class Bread {
private int id;
private String productName;
public Bread() {
}
public Bread(int id, String productName) {
this.id = id;
this.productName = productName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
//存放面包的数组
public class BreadCon {
//存放面包的数组
private Bread[] cons=new Bread[6];
//存放面包的位置
private int index=0;
public synchronized void input(Bread b){//锁this
//判断容器有没有满
while (index>5){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cons[index]=b;
System.out.println(Thread.currentThread().getName()+"生产了"+b.getId()+ "");
index++;
//唤醒
this.notifyAll();
}
public synchronized void output(){//锁this
//判断容器有没有满
while (index<=0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
index--;
Bread b=cons[index];
System.out.println(Thread.currentThread().getName()+"消费了"+b.getId()+ "生产者:"+b.getProductName());
cons[index]=null;
//唤醒生产者
this.notifyAll();
}
}
//生产操作
public class Produce implements Runnable{
private BreadCon breadCon;
public Produce(BreadCon breadCon) {
this.breadCon = breadCon;
}
@Override
public void run() {
for (int i = 0; i <6; i++) {
breadCon.input(new Bread(i,Thread.currentThread().getName()));
}
}
}
//消费操作
public class Consume implements Runnable{
private BreadCon breadCon;
public Consume(BreadCon breadCon) {
this.breadCon = breadCon;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
breadCon.output();
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
//容器
BreadCon breadCon=new BreadCon();
//创建操作:生产和消费
Produce produce=new Produce(breadCon);
Consume consume=new Consume(breadCon);
//创建生产者和消费者
Thread thread1=new Thread(produce, "北京的生产者");
Thread thread2=new Thread(produce, "上海的生产者");
Thread thread3=new Thread(consume, "南京的消费者");
Thread thread4=new Thread(consume, "天津的消费者");
Thread thread5=new Thread(consume, "太原的消费者");
//启动线程
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
}
原文:https://www.cnblogs.com/Ng3061851/p/14946380.html