黑马程序员-多线程(一)
来源:互联网 发布:淘宝排名优化 编辑:程序博客网 时间:2024/05/24 06:50
多线程的概念:
进程:是一个正在执行中的程序
每一个进程都有一个执行顺序,该顺序是一个执行路径或者叫一个控 制单元
线程:就是进程中的一个独立的控制单元
线程在控制着进程的执行,一个进程中至少有一个线程
例如:
Java虚拟机启动的时候会有一个进程java.exe.
该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码 存在于main方法中。该线程称之为主线程。
扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收 机制的线程。
多线程存在的意义:对程序进行优化
线程的创建方式:
创建线程方式1:
通过对api的查找,java已经提供了对线程这类事物的描述。就Thread 类。
创建线程的第一种方式:继承Thread类。
步骤:
1,定义类继承Thread。
2,复写Thread类中的run方法。
目的:将自定义代码存储在run方法。让线程运行。
3,调用线程的start方法,
该方法两个作用:启动线程,调用run方法。
如下代码:
class Demo extends Thread{public void run(){for(int x=0; x<60; x++)System.out.println("demo run----"+x);}}class ThreadDemo {public static void main(String[] args) {//for(int x=0; x<4000; x++)//System.out.println("Hello World!"); Demo d = new Demo();//创建好一个线程。//d.start();//开启线程并执行该线程的run方法。d.run();//仅仅是对象调用方法。而线程创建了,并没有运行。 for(int x=0; x<60; x++)System.out.println("Hello World!--"+x);}}
发现每次运行结果都不同,因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行,明确一点,在某一时刻,只能有一个程序在运行(多核除外),cpu在做着快速切换,已达到看上去是同时运行的效果
我们可以把多线程的运行行为形象的看做是在互相抢夺cpu的执行权
这就是多线程的一个特性:随机性,谁抢到谁执行,至于执行多长由cpu说了算.
为什么要覆盖run方法呢?
Thread类用于描述线程
该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法.也就是说Thread类中的run方法是用于存储线程要运行的代码
线程练习1:创建两个线程,和主线程交替运行
代码如下:
class ThreadA extends Thread //创建线程A{//private String name;public ThreadA(String name) {this.name=name;super(name);}public void run(){for(int x=0;x<100;x++)System.out.println(name+"====="+x);}}public class ThreadTest1 {public static void main(String[] args) {ThreadA a1=new ThreadA("A线程运行");ThreadA a2=new ThreadA("B线程运行");a1.start();a2.start();for(int x=0;x<100;x++)System.out.println("主线程运行======"+x);}}
线程的四种状态+一种特殊状态:
如下图:
创建线程方式2: 实现Runable接口
步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法。
将线程要运行的代码存放在该run方法中。
3.通过Thread类建立线程对象。
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象传递给Thread的构造函数?
因为,自定义的run方法所属的对象是Runnable接口的子类对象,
所以要让线程去指定指定对象的run方法。就必须明确该run方法所属 对象。
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
两种方式的区别:
继承Thread:线程代码存放在Thread子类run方法中.
实现Runnable:线程代码存放在接口的子类的run方法中
多线程的安全问题:
如下代码:
/* * 需求:简单的卖票程序,多个窗口同时卖票 * */class Ticket1 implements Runnable{private int tick =100;private boolean flag=true;public void run(){while(flag){if(tick>0){try {Thread.sleep(20);/*如果这里把线程sleep后悔打印出-1,-2等错票,多线程的运行出现了安全问题 */} catch (Exception e) {// TODO: handle exception}System.out.println(Thread.currentThread().getName()+": 要票的赶紧的,还剩:"+tick--+"张票了");}else {System.out.println(Thread.currentThread().getName()+": 票卖完了");flag=false;}}}}public class ThreadDemo3 {public static void main(String[] args) {Ticket1 t=new Ticket1();Thread t1=new Thread(t);Thread t2=new Thread(t);Thread t3=new Thread(t);Thread t4=new Thread(t);t1.start();t2.start();t3.start();t4.start();}}
通过分析,发现打印出0,-1,-2等错票.
多线程的运行出现了安全问题
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完的时候另一个线程参与进来执行,导致共享数据的错误.
解决办法:
对多条操作共享数据的语句,只有让一个线程都执行完的时候,其他线程才能执行,在执行过程中不允许其他线程执行
Java对于多线程的安全问题提供了专业的解决方式,就是同步代码块:
Synchronized(对象)
{
需要被同步的代码;
}
对象如同锁,持有锁的线程可以在同步中执行,
没有持有锁的线程即使获取cpu的执行权也进不去,因为没有锁
就如同火车上的卫生间------很经典
同步的前提:
1.必须要有两个或者两个以上的线程.
2.必须是多个线程使用同一个锁.
3.必须保证同步中只有一个线程在运行.
好处:解决了多线程的安全问题
弊端:多消耗了资源,因为每次都要判断同步中师父有其他线程
同步函数:
把synchronized放在函数上作为修饰符后,那么该函数就是同步函数
同步函数用的是哪一个锁呢?
函数需要被对象调用。那么函数都有一个所属对象引用。就是this。
所以同步函数使用的锁是this。
通过该程序进行验证:
使用两个线程来买票。
一个线程在同步代码块中。
一个线程在同步函数中。
都在执行卖票动作。
如下代码:
class Ticket implements Runnable{private int tick = 100;Object obj = new Object();boolean flag = true;public void run(){if(flag){while(true){synchronized(this){if(tick>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);}}}}elsewhile(true)show();}public synchronized void show()//this{if(tick>0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);}}} class ThisLockDemo{public static void main(String[] args) {Ticket t = new Ticket();Thread t1 = new Thread(t);Thread t2 = new Thread(t);t1.start();try{Thread.sleep(10);}catch(Exception e){}t.flag = false;t2.start();}}
死锁:
同步中嵌套同步,而锁却不同
如下代码:
class DieLock implements Runnable{private boolean flag;public DieLock(boolean flag) {this.flag=flag;}public void run(){if (flag) {synchronized (MyLock.locka) {System.out.println("if=====locka");synchronized (MyLock.lockb) {System.out.println("if=====lockb");}}}else {synchronized (MyLock.lockb) {System.out.println("else=====lockb");synchronized (MyLock.locka) {System.out.println("else=====locka");}}}}}class MyLock{static Object locka=new Object();static Object lockb=new Object();}public class DieLockDemo {public static void main(String[] args) {Thread t1=new Thread(new DieLock(true));Thread t2=new Thread(new DieLock(false));t1.start();t2.start();}}
- 黑马程序员 多线程(一)
- 黑马程序员--多线程(一)
- 黑马程序员-多线程(一)
- 黑马程序员_JAVA多线程(一)
- 黑马程序员_多线程一
- 黑马程序员 多线程(一)。
- 黑马程序员_多线程(一)
- 黑马程序员-------多线程(一)
- 黑马程序员---多线程(一)
- 黑马程序员——多线程(一)
- 黑马程序员学习日记----多线程(一)
- 黑马程序员--.Net多线程总结(一)
- 黑马程序员 java多线程笔记(一)
- 【黑马程序员】多线程(一) 第十一天
- 黑马程序员——多线程(一)
- 黑马程序员——多线程(一)
- 黑马程序员 JAVA基础 - 多线程(一)
- 黑马程序员——多线程(一)
- hibernate之关于Hibernate的一级、二级缓冲
- 实现isalpha的功能
- Python核心编程读书笔记
- OpenGL小探:显示列表
- 黑马程序员-day26网络编程2
- 黑马程序员-多线程(一)
- 结构体对齐
- POJ 1979 Red and Black (深搜)
- 忘记了root密码,强行进入!更以前的RHEL5,6不太相同
- 程序员如何快速准备面试中的算法
- 完数
- 实现isdigit的功能
- Unable to execute dex: Multiple dex files define 解决方法
- Single Round Match 524 Round 1 - Division I, Level Two LongestSequence