黑马程序员__java基础__多线程
来源:互联网 发布:qq飞车改车吧 软件 编辑:程序博客网 时间:2024/04/30 04:30
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多线程的描述
一.进程、线程
(1)进程:一个正在执行的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
(2)线程:进程中一个负责程序的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。
二.多线程
(1)多线程:在java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线程,还有负责垃圾回收机制的线程。像种在一个进程中有多个线程执行的方式,就叫做多线程。
(2)多线程的好处:解决了多部分代码同时运行的问题,提高程序执行效率。
多线程的创建
一.继承方式(继承Thread)
(1)步骤:1. 定义一个类继承Thread类。
2. 覆盖Thread类中的run方法。
3. 直接创建Thread的子类对象创建线程。
4. 调用start方法开启线程并调用线程的任务run方法执行。
2. 覆盖Thread类中的run方法。
3. 直接创建Thread的子类对象创建线程。
4. 调用start方法开启线程并调用线程的任务run方法执行。
(2)分析:1. Thread类中的run方法,用于存储线程要运行的代码,所以自定义线程就必须复写run方法。
2.如果线程直接调用run方法,等同于只有一个线程(main)在执行。所以必须要调用start方法才能启动线程。
(3)例子:
/** * 创建两个线程,并输出结果 * @author Administrator */class Test extends Thread//继承thread类{String name;Test(String name){this.name=name;}public void run()//复写run方法{for(int x=0;x<60;x++){System.out.println(name+"x="+x);}}}public class ThreadTest {public static void main(String[] args) {Test t1=new Test("线程1---");//创建线程Test t2=new Test("线程2------");t1.start();//启动线程t2.start();for(int x=0;x<60;x++)//main线程{System.out.println("main线程-"+"x="+x);}}}输出结果为:
通过结果可看出:执行是随机、交替执行的。
二.实现方式(实现Runnable)
(1)步骤: 1. 定义类实现Runnable接口。
2. 覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3. 通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
2. 覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3. 通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
4. 调用线程对象的start方法开启线程。
(2)分析: 1. 为什么要将Runnable接口的子类对象传递给Thread的构造函数?因为线程的任务都封装在Runnable接口子类对象 的run方法中。所以要在线程对象创建时就必须明确要运行的任务。
2. 实现的方式避免了Java单继承的局限性。所以,创建线程时用实现的方式较为常见。
(3)例子:
/** * 创建两个线程,并输出结果 * @author Administrator */class Test implements Runnable//实现Runnable接口{public void run()//复写run方法{for(int x=0;x<60;x++){System.out.println(Thread.currentThread().getName() + "-----" + x);}}}public class ThreadTest {public static void main(String[] args) {Test t=new Test();//创建Runnable子类对象Thread d1=new Thread(t);//创建线程并把Runnable子类对象作为实际参数传给Thread的构造函数Thread d2=new Thread(t);d1.start();//启动线程d2.start();for(int x=0;x<60;x++)//main线程{System.out.println("main线程-"+"x="+x);}}输出结果为:
线程的安全问题
一.安全问题出现的原因
(1)多个线程在操作共享的数据。
(2)操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
(2)操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
二.解决办法——同步
(1)同步代码块:格式 synchronized(对象){ 需要被同步的代码;}。其中的对象可以new一个Object对象传进去。
(2)同步函数:格式:在函数上加上synchronized修饰符即可。
(3)同步的前提:1.必须要有两个或者两个以上的线程。2.必须是多个线程使用同一个锁。
(4)同步的利弊:利:解决了多线程的安全问题。弊:多个线程需要判断锁,较为消耗资源。
(5)同步要注意的问题:1.明确哪些代码是多线程运行代码。
2.明确共享数据。
3. 明确多线程运行代码中哪些语句是操作共享数据的。
(6)多线程下的单例模式:
class Single{private static Single s = null; private Single(){} public static Single getInstance() { if(s ==null) { synchronized(Single.class) { if(s == null) s = new Single(); } } return s ; }}
死锁
一.死锁的出现
当同步中嵌套同步时,就有可能出现死锁现象。
二.死锁示例
/**写一个死锁程序*/class LockTest implements Runnable//定义一个类来实现Runnable,并复写run方法{static Object locka = new Object(); static Object lockb = new Object();private boolean flag;LockTest(boolean flag){this.flag=flag;}public void run(){if(flag){while(true){synchronized(locka)//a锁{System.out.println("------if_locka");synchronized(lockb)//b锁{System.out.println("------if_lockb");}}}}else{while(true){synchronized(lockb)//b锁{ System.out.println("------else_lockb");synchronized(locka)//a锁{ System.out.println("------else_locka");}}}}}}public class DeadLock {public static void main(String[] args) {new Thread(new LockTest(true)).start();new Thread(new LockTest(false)).start();}}
线程间通信
一.多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信。二.等待/唤醒机制涉及的方法:
(1) wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。
(2) notify():唤醒线程池中的一个线程(任何一个都有可能)。
(3) notifyAll():唤醒线程池中的所有线程。
(2) notify():唤醒线程池中的一个线程(任何一个都有可能)。
(3) notifyAll():唤醒线程池中的所有线程。
三.wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中
(1)这些方法存在与同步中。
(2)使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。
(3)锁可以是任意对象,所以任意对象调用的方法一定定义object类中。
四.wait(),sleep()有什么区别
(1)wait:释放执行权,释放锁。(2) sleep:释放执行权,不释放锁。
线程的停止
一.让run方法结束
(1)开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让run方法结束,也就是线程结束。
(2)run方法中有如下代码,设置一个flag标记。
public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"....run"); } }二.线程处于冻结状态
(1)线程处于了冻结状态,无法读取标记。
(2)Thread类提供该方法interrupt()强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
(3)例子:
class StopThread implements Runnable{private boolean flag =true;public void run(){while(flag){System.out.println(Thread.currentThread().getName()+"....run");}}public void changeFlag(){flag = false;}}class StopThreadDemo{public static void main(String[] args) {StopThread st = new StopThread(); <span style="white-space:pre"></span>Thread t1 = new Thread(st); <span style="white-space:pre"></span>Thread t2 = new Thread(st); <span style="white-space:pre"></span>t1.start(); <span style="white-space:pre"></span>t2.start();int num = 0;while(true){if(num++ == 60){t1.interrupt();//清除冻结状态t2.interrupt();st.changeFlag();//改变循环标记break;}System.out.println(Thread.currentThread().getName()+"......."+num);}System.out.println("over");}}
0 0
- 黑马程序员__Java基础__多线程
- 黑马程序员__JAVA基础__多线程
- 黑马程序员__java基础__多线程
- 黑马程序员__JAVA基础__语句
- 黑马程序员__JAVA基础__函数
- 黑马程序员__JAVA基础__数组
- 黑马程序员__JAVA基础__集合(一)
- 黑马程序员__JAVA基础__集合(二)
- 黑马程序员__JAVA基础__其他对象
- 黑马程序员__JAVA基础__网络编程
- 黑马程序员__JAVA基础__正则表达式
- 黑马程序员__java基础__反射
- 黑马程序员__java基础__函数、数组
- 黑马程序员__java基础__网络编程
- 黑马程序员__java基础__数组
- 黑马程序员__JAVA基础__面向对象(一)
- 黑马程序员__JAVA基础__面向对象(二)
- 黑马程序员__JAVA基础__面向对象(三)
- POJ2182 -- 线段树
- 内存泄露
- redis 学习笔记(1)-编译、启动、停止
- 推荐 11 款 React Native 开源移动 UI 组件
- Javascrip的应用
- 黑马程序员__java基础__多线程
- iOS动画浅析
- 第十五周 课后实践:阅读程序2
- Java并发编程基础构建模块(02)——并发容器
- python中read() readline()以及readlines()区别
- 网关、路由器、DNS等网络术语的通俗比喻
- git 去掉已经暂存的无用文件
- 轻松拿到登录用户的cookie
- C实现 LeetCode->4Sum