多线程学习
多线程:实现多线程有三种方法
- 继承Thread类
- 实现runnable接口
- 实现callable接口
继承Thread类
线程开启不一定立即执行,这里定义的TestThread1线程与主线程同时进行,运行结果每次都不一样!
//继承Thread来创建线程
public class TestThread01 extends Thread{
@Override
//必须先重写run方法,否则报错
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
TestThread01 testThread01 = new TestThread01();
//调用start方法开启线程
testThread01.start();
for (int i = 0; i < 1000; i++) {
System.out.println("我在学习多线程--"+i);
}
}
}
实现runnable接口
创建runnable实现类的对象,再创建Thread 的对象,通过Thread 的对象代理开启线程!
//实现runnable接口来创建线程,重写run方法
public class TestThread02 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
TestThread02 testThread02 = new TestThread02();
//创建Thread对象,代理开启线程
Thread thread = new Thread(testThread02);
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println("我在学习多线程--"+i);
}
}
}
多线程模拟龟兔赛跑
public class TestThread03 implements Runnable{
//胜利者名字
private String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//判断游戏是否结束
boolean flag;
flag = gameOver(i);
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子")){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果游戏结束,退出循环
if (flag){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
public boolean gameOver( int steps){
if (winner!=null){
return true;
}else {
if (steps>=100){
winner = Thread.currentThread().getName();
System.out.println("winner is :"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
TestThread03 testThread03 = new TestThread03();
new Thread(testThread03,"兔子").start();
new Thread(testThread03,"乌龟").start();
}
}
不安全案例:买票模拟
//不安全买票实例
public class UnSafeBuyTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"a").start();
new Thread(buyTicket,"b").start();
new Thread(buyTicket,"c").start();
}
}
class BuyTicket implements Runnable{
//票数
private int ticketNums = 10;
//判断还有无票的标志
boolean flag = true;
@Override
public void run() {
//如果有票,就调用buy()方法
while(flag){
buy();
}
}
//如果票数小于1,则没有票了
private void buy(){
if (ticketNums<=0){
flag = false;
return;
}
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--);
}
}
结果:发现有人拿到了-1票以及拿到相同的票!
原因:线程不同步,导致了线程的安全
解决办法:加入锁机制,使得线程同步,关键字为synchronized
public class SafeBuyTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"a").start();
new Thread(buyTicket,"b").start();
new Thread(buyTicket,"c").start();
}
}
class BuyTicket implements Runnable{
//票数
private int ticketNums = 10;
//判断还有无票的标志
boolean flag = true;
@Override
public void run() {
//如果有票,就调用buy()方法
while(flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//如果票数小于1,则没有票了
//加入锁机制,线程同步,不会出现危险
private synchronized void buy() throws InterruptedException {
if (ticketNums<=0){
flag = false;
return;
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--);
}
}
注意:锁的对象为增删改的对象
死锁
死锁:当两个进程都要获得对方的东西时,停止等待导致进程僵化
public class DeadLock {
public static void main(String[] args) {
HuaZhuang g1 = new HuaZhuang(0,"小红");
HuaZhuang g2 = new HuaZhuang(1,"小方");
g1.start();
g2.start();
}
}
class KouHong{
}
class Mirror{
}
class HuaZhuang extends Thread{
//加入static保证只有一个
static KouHong kouHong = new KouHong();
static Mirror mirror = new Mirror();
private int choice ;
String girlName;
//构造方法
public HuaZhuang(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
//化妆的方法
//这里上锁不能在同一个锁里,会导致死锁
private void huazhuang() throws InterruptedException {
if (choice==0){
synchronized (kouHong){
System.out.println(this.girlName+"获得口红");
}
Thread.sleep(100);
synchronized (mirror){
System.out.println(this.girlName+"获得镜子");
}
}else {
synchronized (mirror){
System.out.println(this.girlName+"获得镜子");
}
Thread.sleep(100);
synchronized (kouHong){
System.out.println(this.girlName+"获得口红");
}
}
}
@Override
public void run() {
try {
huazhuang();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
显示锁lock,通过调用java.util.concurrent.locks.ReentrantLock包定义一个锁对象,再通过开锁,解锁的方式实现
import java.util.concurrent.locks.ReentrantLock;
public class Lock implements Runnable{
public static void main(String[] args) {
Lock lock = new Lock();
new Thread(lock).start();
}
private int ticketNums = 10;
//定义一个锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
//使用try/finally的方式来使用lock锁,
try{
//开锁
lock.lock();
if (ticketNums>0){
System.out.println(ticketNums--);
Thread.sleep(100);
}else{
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}
}
}
}
线程通信
wait()方法:让线程等待,直到其他线程通知,才会释放锁
notify()方法:唤醒一个处于等待的线程