多线程
☀并发与并行
☀进程概念
☀线程概念
☀线程调度
☀主线程
ps:单线程的缺点就是当代码中出现异常,那么之后的代码将运行不了
☀创建Thread类的子类
public class ThreadClass extends Thread{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println("run" + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
ThreadClass thr = new ThreadClass();
thr.start();
for (int i = 0; i < 50; i++) {
System.out.println("main" + i);
}
}
}
ps:上面的循环次数如果太少,可能看不到main和run抢占cpu执行的过程…
☀实现runnable接口
public class RunnableClass implements Runnable{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
public class RunnableObj {
public static void main(String[] args) {
RunnableClass newObj = new RunnableClass();
Thread newThread = new Thread(newObj);
newThread.start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
☀Thread和Runnable的区别
☀匿名内部类方式实现线程的创建
public class EnoClass {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "--> 小新");
}
}
}.start();
Runnable rn = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "--> 风间");
}
}
};
new Thread(rn).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + "--> 妮妮");
}
}
}).start();
}
}
☀多线程内存图
☀Thread类的常用方法
获取线程名称的方法
1.直接getName
public class Thread01 extends Thread{
@Override
public void run() {
String name = getName();
System.out.println(name);
}
}
public class Thread02 {
public static void main(String[] args) {
Thread01 thr01 = new Thread01();
thr01.start();
new Thread01().start();
}
}
2.借助currentThread和getName
public class Thread01 extends Thread{
@Override
public void run() {
Thread thread = Thread.currentThread();
String name = thread.getName();
System.out.println(name);
/*System.out.println(Thread01.currentThread().getName());链式编程*/
}
}
public class Thread02 {
public static void main(String[] args) {
Thread01 thr01 = new Thread01();
thr01.start();
new Thread01().start();
}
}
设置线程名称的方法(了解即可)
public class SetNameThread extends Thread{
public SetNameThread() {
}
public SetNameThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class SetName {
public static void main(String[] args) {
SetNameThread newThread = new SetNameThread();
newThread.setName("小新");
newThread.start();
new SetNameThread("妮妮").start();
}
}
sleep方法
public class SleepDemo {
public static void main(String[] args) {
for (int i = 0; i < 60; i++) {
System.out.println(i);
try {
Thread.sleep(1000); //单位:毫秒,需要抛出异常或者try...catch
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
☀线程安全问题
图解和代码实现
public class RunnableClass implements Runnable{
private int tickNum = 100;
@Override
public void run() {
while (true) {
if(tickNum > 0) {
try {
Thread.sleep(10); //不用sleep的时候会重复卖票,用sleep出现负数和0,具体原因待定
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--> 正在卖第" + tickNum + "张票。");
tickNum--;
}
}
}
}
public class RunnableObj {
public static void main(String[] args) {
RunnableClass run = new RunnableClass();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.start();
thread2.start();
thread3.start();
}
}
但是这里面用的死循环我有点难理解,就算代码执行完了,由于是死循环,系统依旧一直在判定是否满足执行条件,这样会大大浪费系统资源,所以待定看看。目前看来,个人猜想,这样做的原因是因为执行的次数未知(因为可能有重复的票以及负数和0的票),所以才选择这样的方式。
原理
解决方法一——同步代码块
图解及代码实现
public class RunnableClass implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if(ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
}
}
}
}
public class NewObj {
public static void main(String[] args) {
RunnableClass run = new RunnableClass();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.start();
thread2.start();
thread3.start();
}
}
原理
解决方法二——同步方法
public class RunnableClass implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
method();
}
}
public synchronized void method() {
if(ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
}
}
public class NewObj {
public static void main(String[] args) {
RunnableClass run = new RunnableClass();
Thread thread1 = new Thread(run);
Thread thread2 = new Thread(run);
Thread thread3 = new Thread(run);
thread1.start();
thread2.start();
thread3.start();
}
}
ps:验证锁对象是否为this
public class RunnableClass implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (this) {
method();
}
}
}
public /*synchronized*/ void method() {
if(ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
}
}
静态同步方法
public class RunnableClass implements Runnable{
private static int ticket = 100; //变量也要是静态的
@Override
public void run() {
while (true) {
synchronized (this) {
method();
}
}
}
public static synchronized void method() { //静态同步方法
if(ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
}
}
}
解决方法三——Lock锁
public class RunnableClass implements Runnable{
private int ticket = 100;
Lock newLock = new ReentrantLock(); //多态
@Override
public void run() {
while (true) {
newLock.lock();
if(ticket > 0) {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
newLock.unlock();
}
}
}
}
}
☀线程状态概述
☀等待唤醒案例分析
代码实现
public class NewClass {
public static void main(String[] args) {
Object obj = new Object();
new Thread() {
@Override
public void run() {
System.out.println("我想要一份烧饼");
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("吃完了,很好吃");
}
}
}
}.start();
new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println("烧饼做好了,吃吧");
obj.notify();
}
}
}.start();
}
}
想要重复执行用while(true)死循环。
☀Object类中wait带参方法和notifyAll方法
public class NewClass {
public static void main(String[] args) {
Object obj = new Object();
new Thread() {
@Override
public void run() {
System.out.println("顾客1:我想要一份烧饼");
synchronized (obj) {
try {
obj.wait(6000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("顾客1:吃完了,很好吃");
}
}
}
}.start();
new Thread() {
@Override
public void run() {
System.out.println("顾客2:我想要一份烧饼");
synchronized (obj) {
try {
obj.wait(6000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("顾客2:吃完了,很好吃");
}
}
}
}.start();
new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
System.out.println("烧饼做好了,吃吧");
obj.notifyAll();
}
}
}.start();
}
}
☀等待唤醒机制
public class Baozi {
String pi;
String xian;
boolean isExist = false;
}
public class BaoZiPu extends Thread{
private Baozi bz;
public BaoZiPu(Baozi bz) {
this.bz = bz;
}
@Override
public void run() {
int count = 0;
while(true) {
synchronized (bz) {
if (bz.isExist == true) {
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(count % 2 == 0) {
bz.pi = "薄皮";
bz.xian = "韭菜馅";
}else {
bz.pi = "厚皮";
bz.xian = "猪肉馅";
}
count++;
System.out.println("包子铺在生产" + bz.pi + bz.xian + "包子");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bz.isExist = true;
bz.notify();
System.out.println("包子铺生产好了:" + bz.pi + bz.xian + "包子");
}
}
}
}
public class Chihuo extends Thread{
private Baozi bz;
public Chihuo(Baozi bz) {
this.bz = bz;
}
@Override
public void run() {
while(true) {
synchronized (bz) {
if(bz.isExist == true) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我开吃了");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bz.isExist = false;
bz.notify();
System.out.println("吃完了");
}else {
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public class DetectDemo {
public static void main(String[] args) {
Baozi bz = new Baozi();
new BaoZiPu(bz).start();
new Chihuo(bz).start();
}
}