黑马程序员_api-线程及单例设计模式
a.明确以下概念:
1.进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或叫一个控制单元。
2.线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行,一个进程中至少有一个线程。
3.多线程:如果一个进程中存在着多个控制单元,那么这个进程是一个多线程的应用程序。JVM启动时是一个多线程。
b.创建线程的两种方式
1. java已经提供了对线程这类事物的描述。就是Thread类。并且这个类把要运行的代码存放在了run方法中。所以可以自定义一个类,让它继承Thread类,覆写这个类的run方法,就可以了。步骤:
(1).定义类继承Thread。
(2).复写Thread类中的run方法。目的是将自定义代码存储在run方法。让线程运行。
(3).调用线程的start方法.该方法两个作用:启动线程,调用run方法。
需要注意的是,run方法是一个一般方法,它只用来存线程要运行的代码,start方法才能让线程运行。
示例: class Demo extends Thread{ public void run(){ for(int x=0; x<100; x++) System.out.println("demo run----"+x); } } class ThreadDemo { public static void main(String[] args) { //创建好一个线程。 Demo d = new Demo(); //开启线程并执行该线程的run方法 d.start();。 //主线程运行的代码。 for(int x=0; x<100; x++) System.out.println("Hello World!--"+x); } }
运行以上代码发现:自定义线程与主统一线程出现了随机运行的情况。这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。发现自定义线程与主统一线程出现了随机运行的情况。这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。要明确一点:在某一个时刻,只能有一个程序在运行(多核除外),cpu在做着快速的切换,看上去像是在同时运行一样。
2.通过观察发现Thread类的构造方法可以接收一个Runnable接口类型的对像,那么我们可以自定义一个类去实现这个接口,覆与这个接口的run方法,然后将这个对像作为实际参数传递给Thread类的构造函数即可。这样的操作避免了单继承的局限性。步骤:
(1).定义一个类实现Runnable接口,并覆写里面的run方法;
(2).创建Thread类的对像;
(3).将这个类的对像传递给Thread类的构函数;
(4).调用Thread对像的start方法。
<span style="white-space:pre"> </span>示例: //自定义一个类,实现Runnable接口,并覆写run方法。 class Test implements Runnable{ public void run(){ for(int a=0; a<100; a++){ System.out.println("Test--"+x); } } } class Thread_Runnable{ public static void main(String[] args){ //创建Thrread类的对像,将Test对像作传给Thread类的构造函数。 Thread t = new Thread(new Test()); //开启线程。 t.start(); } }
发现我们自定义类中的run方法被执行了!说明我们这样做也可以让线程帮我们运行我们自定义的代码。
c.关于线程的几个方法
(1).static Thread currentThread():获取当前线程对象;
(2).String getName(): 获取该线程名称;
(3).void setName(String name):设置该线程名称。
d.线程的5种状态:
(1).被创建;
(2).运行;
(3).临时状态(有执行资格但没有执行权);
(4).冻结(放弃了执行资格);
(5).消亡。
e.解决线程的安全问题
当一个线程对多条操作共享数据的代码执行的一部分。还没有执行完,另一个线程开始参与执行,这样容易出现安全隐患。在java中为解决这种安全隐患提供了专门的方案。如下介绍:
(1).同步函数
就是在函数的返回值前加上synchronized关键字,它持有的锁是this。
<span style="white-space:pre"> </span>定义示例: class Demo1{ public synchronized void method(){ System.out.println("我是同步函数。"); } }
当同步函数用static修饰时
就是在synchronized前加上static关键字。静态的同步方法,使用的锁是该方法所在类的字节码文件对象, 类名.class。
<span style="white-space:pre"> </span>定义示例: class Demo2{ public static synchronized void method(){ System.out.println("我是用static修饰的同步函数。"); } }
(2).同步代码块
就是对把需要同步的代码放在这个代码块当中,它使用的锁可以是任意对像。
格式:
synchronized(对像){
需要同步的代码;
}
(3).JDK1.5后对同步提供了显示的锁机制
它提供了多线程升级的解决方案,将同步Synchronized替换成现实Lock操作。将Object中的wait,notify notifyAll,替换了Condition对象。该对象可以Lock锁进行获取。在生产者、消费者的案例中实现了本方只唤醒对方的操作。
生产者、消费者示例代码:
class Resource { private String name; private int count = 1;
private boolean flag = false; <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String name)throws InterruptedException{ lock.lock(); try{ while(flag) condition_pro.await();//t1,t2 this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"-----生产者---"+this.name); flag = true; condition_con.signal(); } finally{
<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">//释放锁的动作一定要执行。</span> lock.unlock(); } } public void out()throws InterruptedException{ lock.lock(); try{ while(!flag) condition_con.await(); System.out.println(Thread.currentThread().getName()+"----消费者----"+this.name); flag = false; condition_pro.signal(); } finally{ lock.unlock(); } } } class Producer implements Runnable { private Resource res;
Producer(Resource res){ this.res = res; } public void run(){ while(true){ try{ res.set("+商品+"); } catch (InterruptedException e){
<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">//只为演示代码,省略处理方式。</span>
<span style="white-space:pre"> </span>e.<span style="font-family: Arial, Helvetica, sans-serif;"><strong>printstackTrace();</strong></span><span style="white-space:pre"> </span> } } } } class Consumer implements Runnable{
private Resource res<span style="font-family: Arial, Helvetica, sans-serif;">;</span>
Consumer(Resource res){ this.res = res; } public void run(){ while(true){ try{ res.out(); } catch (InterruptedException e){
<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">//只为演示代码,省略处理方式。</span>
<span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space:pre"> </span>e.</span><strong>printStackTrace</strong>
} } } }
f.单例设计模式
模式就是在日常生活中人们实践过程中总结出来的,用来解决问题最行之有效的方法,它满足了人们复杂的业务需求。java中总的一共有23总设计模式。单例设计模式就是其中一种,解决了一个类在内存中只存在一个对像。
单例设计模式分为两种,都分为以下三步:
步骤:
a.将构造函数私有化;
b.在类中建立一个静态并私有的对像;
c.对外提供公共一个方法可以获取到该对像。
<span style="white-space:pre"> </span>(1).饿汉式 示例: class Single{ private Single(){} private static Single s = new Single(); public static s getInstance(){ return s; } } (2).懒汉式 懒汉式也称作类的延时加载,是方法被调用时对像才初始化。 示例: class Single{ private Single(){} private Single s = null; public void static s getInstance(){ if(s==null){ synchronized(Single.class){ if(s==null){ s = new Single(); } } } return s; } }