1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【Java学习笔记】——多线程

【Java学习笔记】——多线程

时间:2018-08-24 21:25:56

相关推荐

【Java学习笔记】——多线程

[笔记]跟着狂神学Java-多线程篇

线程/进程

我的理解:电脑上执行的一个游戏窗口是一个进程,每个模式或者按钮是一个线程

继承Thread类

一个类继承了Thread类之后,可以重写Thread类中的run方法。

然后通过对该类实例化后的对象调用start() 方法来启动线程。

(当然别忘了导包哈~:java.lang.Thread)

public class TestThread extends Thread {@overridepublic void run() {//重写父类函数体}public static void main(String[] args) {TestThread th = new TestThread();th.start();}}

实现Runnable 接口

一个类实现了Runnable接口之后,必须要实现Runnable接口中的run() 方法。(导包:java.lang.Runnable)

通过实例化该类创建一个对象来调用start() 方法来启动线程。

当然也可以这样来启动new Thread(对象名).start

public class TestThread implements Runnable {@overridepublic void run() {//实现Runnable接口的run() 方法}public static void main(String[] args) {TestThread th = new TestThread();th.start();//new Thread(th).start;}}

实现Callable 接口

因为我还没有学的特别深,目前觉得和Runnable接口差不多,但是会有执行之后的返回值。

(导包:java.util.concurrent.Callable)

具体实现有一下几个步骤:

1. 实现Callable 接口,需要返回值类型

2. 重写call() 方法,需要抛出异常

3. 创建目标对象

4. 创建执行服务

5. 提交执行

6. 获取结果

7. 关闭服务

public class TestThread implements Callable {//实现call() 方法@Overridepublic Object call() throws Exception {//call方法的返回值类型可以修改return null;}//这里也可以选择抛出最高Exceptionpublic static void main(String[] args) throws InterruptedException,ExecutionException {//创建线程池ExecutorService service = Executor.newFixedThreadPool(10);//参数:线程数//创建目标对象TestThread th = new TestThread;//提交执行Future<Boolean> t1 = service.submit(th);Future<Boolean> t2 = service.submit(th);Future<Boolean> t3 = service.submit(th);//也可以这样写//Future<Boolean> t1 = service.submit(new TestThread);//获取结果,需要捕获或者抛出异常,这里我选择抛出System.out.println(t1.get());System.out.println(t2.get());System.out.println(t3.get());//关闭服务service.shutdownNow();}}

线程的并发

并发

多个线程一块启动,但是我们自己的电脑只有一个CPU,然而又因为CPU的执行速度比较快,多个线程看上去像是同时执行,但从围观的角度看是这些线程在交替执行,轮流被CPU处理,这叫并发。并行

同一时刻多条线程在同时执行,一起被CPU所执行,因此需要多个CPU,这叫并发。

Lambda 表达式

了解函数式接口:

只包含了一个抽象方法的接口叫做函数式接口对于函数式接口,我们可以通过Lambda表达式来创建该接口的对象。

public class TestLambda implements Lambda {@Overridepublic void lambda(int a) {System.out.println("This is Function lambda");}public static void main(String[] args) {Lambda myLambda = null;//写法一myLambda = (int a) -> {System.out.println("This is Test1");};//写法二myLambda = (a) -> {System.out.println("This is Test2"); };//写法三(箭头后面如果有多个语句,就必须要用{})myLambda = a -> System.out.println("This is Test3");}}

线程的五大状态及常用方法

1. sleep() 线程休眠2. yield() 线程礼让3. join() 强制执行线程4. 观测线程状态5. 线程的优先级6. 守护线程

观测线程状态

Thread.State,State是Thread类中的一个枚举类,一共有六种状态:NEW(初始化,未启动状态),RUNNABLE(在JVM中执行的线程状态),BLOCKED(被阻塞,等待监视器锁定),WAITTING(等待另一个线程执行),TIME_WAITTING(等待另一个线程执行到指定时间),TERMINATED(已结束)。

//创建一个线程并启动/休眠Thread thread = new Thread();thread.start();//thread.sleep();//创建一个状态对象Thread.State state = thread.getState();//打印状态System.out.println(state);

线程的优先级

(官方预设的三个优先级,线程不设置优先级默认是5)

Thread.MIN_PRIORITY = 1;Thread.NORM_PRIORITY = 5;Thread.MAX_PRIORITY = 10;

Thread thread = new Thread();//参数可以填1-10的数字,也可以填上面三个预设好的常量thread.setPriority(1);

守护线程

/** 用户线程->Son* 守护线程->Father* JVM必须确保用户线程执行完毕* JVM不用等待守护线程执行完毕* */public class ThreadDaemon {public static void main(String[] args) {Father father = new Father();Son son = new Son();//设置守护线程Thread thread = new Thread(father);thread.setDaemon(true);//启动线程thread.start();new Thread(son).start();}}class Father implements Runnable {@Overridepublic void run() {while(true){System.out.println("Father Protect Son");}}}class Son implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("Son is Happy!");}System.out.println("Life ------ Over");}}

线程同步机制

1. 同步方法及同步块2. 死锁3. Lock 锁

同步方法

(synchronized 可重入锁)

public synchronized void method (int args) {}

会产生的问题:

1. 一个线程持有锁会导致其他所有需要此锁的线程挂起(阻塞)。

2. 多线程竞争下,加锁,释放锁会导致调度延时,引起性能问题。

3. 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。

同步块

我跟着狂神做了银行取钱的个小实例,我个人觉得讲的不错,自己加了点修改,因为我照着他打出来的代码老是只有一个线程独占。后来发现是循环的问题,他写的是一个线程执行到结束。

这是我修改后的实例

package Syn;public class Application {public static void main(String[] args) {//创建账户Account account = new Account("结婚基金",1000);Bank you = new Bank(account, 50, "你");Bank wife = new Bank(account, 100, "老婆");you.setPriority(1);you.start();wife.setPriority(10);wife.start();}}class Account {String name;int money;public Account(String name, int money) {this.name = name;this.money = money;}}class Bank extends Thread {Account account;int drawingMoney;int currentMoney = 0;private boolean flag = true;public Bank(Account account, int drawingMoney, String name) {super(name);this.account = account;this.drawingMoney = drawingMoney;}//取钱@Overridepublic void run() {while (flag) {try {withDraw();Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}}}private void withDraw () {synchronized (account) {//判断有没有钱if (account.money - drawingMoney < 0) {System.out.println(Thread.currentThread().getName() + "没钱了,取不了钱");flag = false;return;}//手里的钱currentMoney += drawingMoney;System.out.println(this.getName() + "取了 " + drawingMoney + " 现在手里有 " + currentMoney);//卡里余额account.money -= drawingMoney;System.out.println(account.name + "还剩 " + account.money);}}}

死锁

在线程同步时,会产生死锁的问题。我的理解是一个线程X访问一个资源A的同时还需要去访问另外一份资源B。但是另外一份资源B被Y正在访问中,无法释放锁,同时线程Y也要继续访问资源A,但线程X正在访问,无法释放锁,所以产生了“死结”,谁也不让谁,就导致了线程的卡死。

附上跟狂神一块敲的小实例:

package Syn;public class DeadLock {public static void main(String[] args) {MakeUp g1 = new MakeUp("灰姑娘", 0);MakeUp g2 = new MakeUp("公主", 1);g1.start();g2.start();}}class LipSticks {}class Mirror {}class MakeUp extends Thread {//保证资源只有一份static LipSticks lipSticks = new LipSticks();static Mirror mirror = new Mirror();String name;int choice;MakeUp(String name, int choice) {this.name = name;this.choice = choice;}@Overridepublic void run() {makeUp();}private void makeUp() {if (choice == 0) {synchronized (lipSticks) {System.out.println(this.name+ "获得了口红锁");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//将锁写在锁里面会发生死锁//synchronized (mirror) {//System.out.println(this.name + "获得了镜子锁");//}}//此时不会发生死锁synchronized (mirror) {System.out.println(this.name + "获得了镜子锁");}}else {synchronized (mirror) {System.out.println(this.name + "获得了镜子锁");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}//将锁写在锁里面会发生死锁//synchronized (lipSticks) {//System.out.println(this.name + "获得了口红锁");//}}//此时不会发生死锁synchronized (lipSticks) {System.out.println(this.name + "获得了口红锁");}}}}

Lock锁

(可重入锁)

跟(synchronized)锁功能差不多,比它更高效。

小实例:

package Syn;import java.util.concurrent.locks.ReentrantLock;public class LockTest{public static void main(String[] args) {LockTest2 lockTest2 = new LockTest2();new Thread(lockTest2,"Thread 1").start();new Thread(lockTest2,"Thread 2").start();new Thread(lockTest2,"Thread 3").start();}}class LockTest2 implements Runnable {private int ticket = 100;//创建可重入锁private final ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {try {//加锁lock.lock();if (ticket > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " Get " + ticket--);}else {break;}} finally {//解锁lock.unlock();}}}}

线程协作

生产者和消费者问题

思想:消费者去商店排队买东西,若商店里面有商品,则生产者通知消费者可以开始消费了,若商品消费完毕,则消费者通知生产者生产商品。

解决方法:

1. 管程法2. 信号灯法

管程法

利用缓冲区来完成协作

package TestPC;//消费者/生产者问题--->利用缓冲区解决,管程法public class PcTest {public static void main(String[] args) {SynContainer container = new SynContainer();new Producer(container).start();new Consumer(container).start();}}//消费者class Consumer extends Thread {//创建一个容器SynContainer container;public Consumer (SynContainer container) {this.container = container;}//消费@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("消费了 " + container.pop().id + " 块面包");}}}//生产者class Producer extends Thread {//创建一个容器SynContainer container;public Producer (SynContainer container) {this.container = container;}//生产@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("生产了 " + i + " 块面包");container.push(new Goods(i));}}}//产品class Goods {int id;public Goods(int id) {this.id = id;}}//缓存区,消费发生地class SynContainer {//创建容器大小Goods[] bread = new Goods[10];//商品计数器int count = 0;//生产者放入产品public synchronized void push(Goods goods) {//如果容器满了则通知消费者消费if (count == bread.length) {//通知消费者消费,生产等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没满,则生产者丢入商品bread[count] = goods;count++;//通知消费者消费this.notifyAll();}//消费者消费商品public synchronized Goods pop() {//判断是否能够消费if (count == 0) {//等待生产者生产,消费者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//消费者消费count--;Goods goods = bread[count];//商品消费完,通知生产者生产this.notifyAll();return goods;}}

信号灯法

利用一个标志位flag来判断谁该等待从而达到协作

package TestPC;//消费者/生产者问题---->信号灯法解决public class PcTest2 {public static void main(String[] args) {Bread bread = new Bread();new Baker(bread).start();new Customer(bread).start();}}//生产者---->糕点师class Baker extends Thread{Bread bread;public Baker(Bread bread) {this.bread = bread;}//糕点师生产@Overridepublic void run() {for (int i = 0; i < 20; i++) {if (i%2 == 0) {this.bread.produce("可颂");}else {this.bread.produce("法棍");}}}}//消费者---->顾客class Customer extends Thread{Bread bread;public Customer (Bread bread) {this.bread = bread;}//顾客买面包@Overridepublic void run() {for (int i = 0; i < 20; i++) {this.bread.buy();}}}//产品----> 面包是否有存货作为控制消费和生产的条件class Bread {//面包名字String cake;//判断是否有面包的存货boolean flag = true;//生产者生产中,顾客等待(生产)public synchronized void produce(String cake) {//顾客等待if (!flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//生产System.out.println("糕点师制作了:" + cake);//生产后通知消费者消费this.notifyAll();this.cake = cake;this.flag = !this.flag;}//顾客消费中,生产者等待(消费)public synchronized void buy () {//生产者等待if (flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//消费System.out.println("顾客买了:" + cake);//产品消费完,通知生产者生产this.notifyAll();this.flag = !this.flag;}}

线程池

//创建线程池ExecutorService service = Executor.newFixedThreadPool(10);//参数:线程数

以上都是我跟着狂神学Java多线程时的一些代码和感悟,纯属当作笔记来分享,如果大家发现了我笔记中的错误,可以多多指正,我会认真修改,虚心求教的!(ps:第一次写博客,请多多见谅~)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。