黑马程序员 多线程
来源:互联网 发布:mysql fetch object 编辑:程序博客网 时间:2024/06/06 17:20
——- android培训、java培训、期待与您交流! ———-
1,进程与线程:
进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元。
线程就是进程中的一个独立的控制单元,线程在控制着进程的执行。
注意:jvm启动不止一个线程,除了主线程还有负责垃圾回收机制的线程。
2,创建线程的第一种方式:继承Thread类
(a)创建子类对象的同时就创建了线程,创建多少个子类对象就有多少条线程。
(b)步骤:
(1)定义类继承Thread。
(2)复写Thread类中的run方法。目的:将自定义代码存储在 run方法。让线程运行。
(3)调用线程的start方法。该方法两个作用:启动线程;调用 run方法。
(4)要是只调用run方法,这仅仅是调用对象的方法,而没有启动线程。
(c)多线程有一个特点:随机性。在互相抢夺cpu的执行权。
(d)线程都有自己默认的名称,Thread-编号 该编号从0开始。
static Thread currentThread():获取当前线程对象。
getName(): 获取线程名称。
设置线程名称:setName或者构造函数。
线程的状态图:
体现
public class Thread001 { public static void main(String[] args) { Deme d = new Deme(); d.start(); //开启线程 for (int i = 0; i < 60; i++) {//主线程 System.out.println("main::"+i); } }}class Deme extends Thread{ //继承Thread类 public void run(){ //自定义方法内容 for (int i = 0; i < 60; i++) { System.out.println("Thread::"+i); } }}
结果图:
3,创建线程的第二种方式:实现Runnable接口
步骤:
(a)定义类实现Runnable接口
(b)覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。
(c)通过Thread类建立线程对象
(d)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法。
Ticket类实现了Runnable接口
Ticket t=new Ticket();
Thread t1=new Thread(t)
4,实现方式和继承方式的区别
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable:线程代码存放接口的子类的run方法。实现方式的好处是避免了单继承的局限性。
5,多线程的运行出现安全问题
(a)问题的原因
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就参与进来执行,导致共享数据的错误。
体现:
public class Thread002 { public static void main(String[] args) { Ticket tick = new Ticket(); Thread d1 = new Thread(tick); Thread d2 = new Thread(tick); Thread d3 = new Thread(tick); Thread d4 = new Thread(tick); d1.start();//开启线程 d2.start();//开启线程 d3.start();//开启线程 d4.start();//开启线程// new Thread(tick).start();// new Thread(tick).start();// new Thread(tick).start();// new Thread(tick).start(); }}class Ticket implements Runnable{ private int tick = 100; public void run() { while (true) { //循环 if (tick>0) { try { Thread.sleep(10);//稍微等待 } catch (InterruptedException e) { e.printStackTrace();//处理异常 } System.out.println(Thread.currentThread().getName()+"....."+tick--); } } }}
结果图:
(b)解决办法
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
(c)多线程安全问题的解决办法是同步代码块:
synchronied(对象)
{需要被同步的代码}
对象如同锁。持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。例如,火车上的卫生间。
(d)同步的前提:
(1)必须要有两个或者两个以上的线程。
(2)必须是多个线程使用同一个锁,必须保证同步中只能有一个线程在运行。
(e)同步的优劣性:
(1)解决了多线程的安全问题。
(2)需要判断锁,降低效率。
(f)同步函数的锁是synchronized(this);静态同步函数的锁是synchronized(类名.class)
(g)多线程的单例设计模式
懒汉式的特点是延迟加载实例,在多线程访问时,会出现安全问题,可以使用同步代码块或同步函数来解决,但比较低效,可以通过双重判断的形式来解决低效问题。同步所使用的锁是该类字节码文件对象。
体现:
//多线程单例设计模式—懒汉式 class S { private static S s=null; private S (){}; public static S getIns () { if(s==null) { synchronized(S.class) { if(s==null) s=new S(); } } return s; } }
(h)死锁:同步中嵌套同步,使用不同的锁,万万不可。
体现:
class Test{ public static void main(String[] args) { Thread t1 = new Thread(new Run(true)); Thread t2 = new Thread(new Run(false)); t1.start(); t2.start(); }}class Run implements Runnable{ private boolean flag; public Run(boolean flag) { this.flag = flag; } public void run() { if(flag) { synchronized(LockFactory.lockA)//同步锁A { System.out.println("if.....lockA"); synchronized(LockFactory.lockB)//同步锁B { System.out.println("if.....lockB"); } } }else { synchronized(LockFactory.lockB)//同步锁B { System.out.println("else...lockB"); synchronized(LockFactory.lockA)//同步锁A { System.out.println("else...lockA"); } } } }}class LockFactory//用于提供锁的类{ static LockA lockA = new LockA(); static LockB lockB = new LockB();}class LockA//锁A{}class LockB//锁B{}
6,生产者与消费者的经典实例:
对于多个生产者和消费者,需要定义while判断标记。因为要让被唤醒的线程再一次判断标记。为什么定义notifyAll,因为需要唤醒对方线程。因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
毕老师视频中使用whlie,wait,notifyAll解决问题,我觉得在那个例子上只需改动判断条件即可实现。
体现:
public class Thread003 { public static void main(String[] args) { R r=new R(); P p = new P(r); C c = new C(r); Thread t1 = new Thread(p); Thread t2 = new Thread(p); Thread t3 = new Thread(c); Thread t4 = new Thread(c); t1.start(); t2.start(); t3.start(); t4.start(); }}class R{ private String name; private int count = 1; private boolean flag = true; public synchronized void set(String name){ if (flag) { this.name = name + "---" + count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+ this.name); flag = false; } } public synchronized void out(){ if (!flag) { System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name); flag = true; } } }class P implements Runnable{ private R r; P(R r){ this.r=r; } public void run() { while (true) { r.set("++商品++"); } }}class C implements Runnable{ private R r; C(R r){ this.r=r; } public void run(){ while (true) { r.out(); } } }
7,JDK1.5升级
JDK1.5中提供了多线程升级解决方案,将同步Synchronized替换成显示的Lock操作。将Object中的wait,notify,notifyAll,替换了Condition对象:await(),signal(),signalAll()。
8,停止线程
定义循环结束标记:因为线程运行代码一般都是循环,只要控制了循环即可。
使用interrupt(中断)方法:该方法是结束线程的交结状态,使线程回到运行状态中来。
注:stop方法已经过时不再使用。
9,守护线程
setDaemon(boolean on),该方法必须在启动线程前调用。守护线程依赖于主线程,当主线程运行结束,守护线程也跟着结束。
Thread t=new Thread(d);
t.setDaemon(true);
t.start();
10,join()方法
当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行。join可以用来临时加入线程执行。
11,优先级
t1.setPriority(Thread.MAX_PRIORITY);最高优先级
t2.setPriority(Thread.MIN_PRIORITY);最低优先级
t3.setPriority(Thread.NORM_PRIORITY);默认优先级
——- android培训、java培训、期待与您交流! ———-
- 黑马程序员 多线程
- 黑马程序员:多线程
- 黑马程序员-java多线程
- 黑马程序员--java 多线程
- 黑马程序员_java多线程
- 黑马程序员-java多线程
- 黑马程序员_多线程
- 黑马程序员 多线程
- 黑马程序员_JAVA多线程
- 黑马程序员—多线程
- 黑马程序员- 多线程
- 黑马程序员_多线程
- 黑马程序员--多线程
- 黑马程序员_多线程
- 黑马程序员--Java多线程
- 黑马程序员---多线程
- 黑马程序员__多线程
- 黑马程序员_多线程
- Contest 7 1011 Mahjong tree【递归/树】
- 关于vmware虚拟机中ubuntu下使用minicom
- 一个测试 unix 时间戳的程序
- 设计模式—工厂模式(Factory Pattern)
- 继承与base
- 黑马程序员 多线程
- 《算法导论》第一讲
- Ural1114 Boxes【DP】
- 129. Sum Root to Leaf Numbers
- 归并排序
- 如何实现文件的断点续传,文件下载
- SQLServer With As 用法
- HDU 2563 统计问题(递推)
- HDU-2111 Saving HDU