多线程
来源:互联网 发布:学车网络招生平台 编辑:程序博客网 时间:2024/06/07 01:14
每一个进程执行都有一个执行程序,该顺序是一个执行路径,或者叫一个控制单元
线程:进程中的一个独立控制单元.
线程在控制着进程的执行
一个进程中至少有一个线程
JAVA VM 启动的时候会有一个进程 java.exe
该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于 main 方法中
该线程称之为主线程,主线程执行 main()方法中的代码。
多线程 (举例:迅雷下载)
扩展:JVM启动不止一个线程,还有负责垃圾回收机制的线程
如何在自定义代码中,自定义一个线程?? (Thread 类)
创建新线程第一种方式:继承Thread 类
步骤:
1、定义类继承Thread;
2、重写Thread
类的run()
方法;
目的:将自定义的代码存储在run()方法中,让线程运行。
3、调用线程 start()方法:该方法两个作用:启动线程;调用run()方法;
每次运行结果都不同,因为多个线程都获取CPU的执行权,CPU执行到谁,谁就运行。
某一个时刻,只能有一个程序在运行。(多核除外,多核的瓶颈为内存大小)
CPU在做着快速的切换,以达到看上去是同时运行的效果。
可以形象的把多线程的运行行为看做是互相抢夺CPU的执行权。
多线程特性;随机性。谁抢到谁执行,至于执行多长,CPU说的算。
为什么要覆盖 run() 方法?
Thread 类用于描述线程,该类定义了一个功能,用于存储线程要运行的代码,该存储功能的就是
run() 方法 ,也就是说Thread 类中的run()方法,用于存储线程要运行的代码。
public class ThreadDemo {public static void main(String[] args) {Demo d = new Demo(); //创建一个线程d.start(); //start()方法,启动线程并执行该线程的run()方法 d.run(); //仅仅是对象调用,线程创建了,但是并没有运行for(int i = 0; i < 50; i++)System.out.println("Hello World--" + i);}}class Demo extends Thread {public void run() {for(int i = 0; i < 50; i++)System.out.println("Demo Run --" + i);}}线程的运行状态:
获取线程对象及名称:
线程都有自己的名称,Thread-编号为线程的默认名称,通过调用 getName()获得;
Static ThreadcurrentThread() :获取当前线程对象;
getName():获取线程名称;
设置线程名称:setName() 或者使用super()调用父类构造函数;
创建线程的第二种方式:实习Runable接口
步骤:
1、 定义类实现Runable接口
2、 覆盖Runable接口中的run()方法
将线程要运行的代码存放在run()方法中。
3、 通过Thread类建立线程对象
4、 将Runable接口的子类对象作为实际参数传递给Tread类的构造函数
为什么要将Runable接口的子类对象传递给Thread的构造函数。
因为自定义的run()方法所属的对象是Runable接口的子类对象
所以要让线程去调用指定对象的run()方法,就必须明确该run()方法所属对象。
5、 调用Thread类的start()方法开启并调用Ruanable接口子类的run()方法;
实现方式和继承方式有什么区别?
实现方式好处:避免了单继承的局限性。
在定义线程时,建议使用实现方式;
两种方式区别:
继承Thread :线程代码存放在Thread子类run()方法;
实现Runable,线程代码存放在接口的子类run()方法中。
//多个窗口同时售票class Ticket implements Runable //定义类实现Runable 接口{private int tick = 100;public void run() ///重写run()方法{while(true){if(tick > 0){System.out.println(Thread.currentThread().getName() + "sale```" + tick--);}}}}public class TicketDemo {public static void main(String[] args) {Ticet t = new Ticket();Thread t1 = new Thread(t); //通过Thread 类建立线程对象Thread t2 = new Thread(t); Thread t3 = new Thread(t);Thread t4 = new Thread(t);t1.start(); //通过Thread类的star()方法开启线程,并调用Runable接口子类的run()方法t2.start();t3.start();t4.start();}}
多线程运行中的安全问题:
问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完
另一个线程参与进来执行,导致共享数据的错误。
解决办法:对多条操作共享数据的语句,只能让一个线程执行完毕,在执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供的专业解决方式:同步代码块。
Synchronized(对象)
{
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行,
没有持有锁的线程即使获取了CPU的执行权也进不去,因为没有获取锁。
同步的前提:
1、 必须要有两个或者两个以上的线程。
2、 必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题;
弊端:多个线程都需要判断锁,较为消耗资源。
class Ticket implements Runnable{private int tick = 100; Object obj = new Object()public void run() {while(true){synchronized(obj){if(tick > 0){try{Thread.sleep(10);}catch(InterruptedException e) {e.printStackTrace();} System.out.println(Thread.currentThread().getName() + "-----sale-----" + tick--);}}}}}
/*需求分析:银行有一金库 有2个储户同时往里面存300,每次存100,分3次*/ 如何找问题: 1、明确哪些代码是多线程运行代码; 2、明确共享数据; 3、明确多线程运行代码中哪些语句是操作共享数据的;class Bank {public int sum;Object obj = new Object();public void add(int n) {synchronized(obj){sum = sum + n;try{Thread.sleep(20);}catch(InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"--sum = " + sum);}}}class Customer implements Runnable{private Bank b = new Bank();public void run(){for(int i=0; i<8; i++){b.add(100);}}}public class BankDemo {public static void main(String[] args){Customer c = new Customer();Thread t1 = new Thread(c);Thread t2 = new Thread(c);t1.start();t2.start();}}
同步函数用的是哪一个锁?同步函数需要被对象调用,那么函数都有一个所属对象引用,就是this所以同步函数使用的锁是thisclass 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(100);}catch(InterruptedException e) {e.printStackTrace();} System.out.println(Thread.currentThread().getName() + "-----code-----" + tick--);}}}}elsewhile(true){show();}}public synchronized void show(){if(tick > 0){try{Thread.sleep(10);}catch(InterruptedException e) {e.printStackTrace();} System.out.println(Thread.currentThread().getName() + "-----show-----" + tick--);}}}
如果同步函数被静态修饰后,使用的锁是什么?静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码对象,类名.class,该对象的类型是class.静态的同步方法,使用的锁是该方法所在类的字节码文件对象,即 类名.classclass Ticket implements Runnable{private int tick = 100; Object obj = new Object(); boolean flag = true;public void run() {if(flag){while(true){synchronized(Ticket.class){if(tick > 0){try{Thread.sleep(100);}catch(InterruptedException e) {e.printStackTrace();} System.out.println(Thread.currentThread().getName() + "-----code-----" + tick--);}}}}elsewhile(true){show();}}public static synchronized void show(){if(tick > 0){try{Thread.sleep(10);}catch(InterruptedException e) {e.printStackTrace();} System.out.println(Thread.currentThread().getName() + "-----show-----" + tick--);}}}
/*单例设计模式*///饿汉式class Single{private static final Single s = new Single();private Single() {}pbulic static Single getInstance(){return s;}}//懒汉式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
/*死锁:同步中嵌套同步,而锁却不同*/class Test implements Runnable{private boolean flag = true; Test(boolean _flag){this.flag = _flag;}public void run(){if(flag){while(true){synchronized(MyLock.locka){System.out.println("if locka");synchronized(MyLock.lockb){System.out.println("if lockb");}}}}else{while(true){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 DeadLockDemo{public static void main(String[] args){Thread t1 = new Thread(new Test(true));Thread t2 = new Thread(new Test(false));t1.start();t2.start();}}
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- 多线程
- Operating Systems : Design and implementation 读书笔记
- 通过命令行开启和结束应用程序
- FileChannel 使用
- debian关机时的beep声响
- vector 释放内存 swap
- 多线程
- Java5泛型的用法,T.class的获取和为擦拭法站台
- COOKIE概念的深入理解
- 黑马程序员—JAVA异常特点
- 自用数据库软件(3-2备份还原)
- 黑马程序员—JAVA多线程
- 51单片机中使用ucos ii的优缺点
- 一个小东西
- mysql系统函数 总结