Java day 20-21

来源:互联网 发布:7级防空火箭升级数据 编辑:程序博客网 时间:2024/05/22 12:39

Day20

1.多线程:如果一个程序的执行路径有多条.

单线程:程序的执行路径只有一条

面试题:Jvm,java虚拟机是多线程程序吗?

答:是多线程程序,由于java虚拟机中自带一个垃圾回收器,来确保程序不会轻易的造成内存溢出。

至少开启两条子线程:

当前程序在执行代码的时候,会开启main:主线程

垃圾回收器会开启一个垃圾回收线程,来确保程序不会内存异常,将不用的变量或者没有更多引用的对象来回收掉

2. 如何实现多线程程序?

要实现多线程程序,必须创建一个进程,

创建进程需要调用系统资源进行创建,但是Java语言是不能直接调用系统资源

C/C++语言是可以创建系统资源,然后使用Java语言掉C/C++已经封装好的东西,

Java---->类:Thread类

并发和并行

并发:指的是同一个时间点

并行:指的的是一个时间段

多线程程序实现的第一种方式:

1)自定一个类:MyThread 继承自Thread类

2)在MyThread类中重写Thread类中的run()  :为什么重写run()

3)在主线程中,创建该类的实例对象,启动线程

启动线程不是调用run()方法,

strat()是线程开始执行的方法

run()方法调用相当于调用了一个普通方法,并不会出现线程随机性;而start()方法调用,其实是通过Jvm调用线程中的run()来进行多个线程抢占CPU执行权

如何获取线程的名称?

public final String getName()返回该线程的名称。

设置线程名称

public final void setName(String name)改变线程名称,使之与参数name 相同。

例:

public class ThreadDemo {

         publicstatic void main(String[] args) {

                   //创建该线程的实例对象

                   //MyThread my = new MyThread();

                   //启动线程

                   //启动线程不是调用run()方法,

                   //strat()是线程开始执行的方法

                   //run()方法调用相当于调用了一个普通方法,并不会出现线程随机性;而start()方法调用,

                   //其实是通过Jvm调用线程中的run()来进行多个线程抢占CPU执行权

                   //my.start() ;

                   //第二次启动线程,会出现:非法线程状态异常

                   //当前my线程已经启动了,不能重新启动

                   //my.start();

                   //my.run();

                   //my.run();

                   MyThreadmy1 = new MyThread();

                   MyThreadmy2 = new MyThread();

                   //分别启动线程

                   my1.start();

                   my2.start();

         }

}

 

class MyThread extends Thread {

         //重写Thread类中的run()方法

         publicvoid run() {

                   //耗时的操作,线程睡眠,线程等待,循环语句

                   for(int x = 0; x < 100; x++) {

                            System.out.println(x);

                   }

         }

}

多线程实现的第二种方式:(实际开发中第二种比第一种应用更广泛)

开发步骤:

1)自定义一个类MyRunnable,该类实现Runnable接口

2)实现该接口中的run()方法

3)在主线程中创建该类的实例对象,

4)创建Thread类对象,将3)创建的这个对象作为参数进行传递

5)分别启动线程

例:

public class ThreadDemo2 {

         publicstatic void main(String[] args) {             

                   //1)创建MyRunnable实例对象

                   MyRunnablemy = new MyRunnable();            

                   //2)创建线程类对象

                   //publicThread(Runnable target,String name)

                   Threadt1 = new Thread(my, "线程1");

                   Threadt2 = new Thread(my, "线程2");

                   //启动线程

                   t1.start();

                   t2.start();

         }

}

class MyRunnable implements Runnable {

         publicvoid run() {

                   for(intx = 0 ; x < 100 ; x ++){

                            //在控制台,打印每一个子线程的线程名称

                            //getName()是Thread类中的方法

                            //间接的使用Thread类的静态功能得到线程名称

                            System.out.println(Thread.currentThread().getName()+":"+x);

                   }

         }

}

面试题:多线程的实现方式有几种,分别是什么?

答三个方式,分别阐述

第三种:和线程池有关系(并且和Callable接口有关系)

如果这个题口头问你,那么直说两种可以:继承Thread类,实现Runnable接口

多线程实现的第三种方式:(实际开发中很少用到)

public static ExecutorServicenewFixedThreadPool(int nThreads)

Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程

这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法:

ExecutorsService :接口中的方法<T>Future<T> submit(Callable<T> task)

该返回值表示:异步计算的结果。

例:

importjava.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class CallableDemo {    

         publicstatic void main(String[] args) {             

                   //创建线程池对象,利用工厂类

                   ExecutorServiceThreadpool = Executors.newFixedThreadPool(2);                

                   //提交Callable任务(异步任务)

                   Threadpool.submit(newMyCallable());//相当于线程中的start()方法

                   Threadpool.submit(newMyCallable()); 

                   //结束线程池

                   Threadpool.shutdown();

         }

}

import java.util.concurrent.Callable;

public class MyCallable implementsCallable<Object> {

         //call()方法的返回值是和Callable中的泛型是一致的!

         publicObject call() throws Exception {             

                   for(intx = 0 ; x < 100 ; x ++){

                            System.out.println(Thread.currentThread().getName()+":"+x);

                   }

                   returnnull;               

         }

}

综合例题:三个窗口同时卖出100张票。

方法1:

public class ThreadDemo3 {

         publicstatic void main(String[] args) {

                   Sellticketsst1 = new Selltickets();

                   Sellticketsst2 = new Selltickets();

                   Sellticketsst3 = new Selltickets();

                   st1.setName("窗口1");

                   st2.setName("窗口2");

                   st3.setName("窗口3");

                   st1.start();

                   st2.start();

                   st3.start();

         }

}

 

class Selltickets extends Thread {

         privatestatic int tickets = 100;

         privateObject o = new Object();

         privateDemo d = new Demo();

 

         publicvoid run() {

                   while(true) {

                            synchronized(d) {

                                     if(tickets > 0) {

                                               try{

                                                        Thread.sleep(100);

                                               }catch (InterruptedException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }

                                               System.out.println(getName()+ "正在出售第" + tickets + "张票!");

                                               tickets--;

                                     }

                            }

                   } 

         }

}

 

class Demo {

 

}

方法2:

public class ThreadDemo {

         publicstatic void main(String[] args) {

                   Sellticketsst1 = new Selltickets();

                   Sellticketsst2 = new Selltickets();

                   Sellticketsst3 = new Selltickets();

                   st1.setName("窗口1");

                   st2.setName("窗口2");

                   st3.setName("窗口3");

                   st1.start();

                   st2.start();

                   st3.start();

         }

}

 

class Selltickets extends Thread {

         privatestatic int tickets = 100;

         privatestatic Object o = new Object();

         privatestatic Demo d = new Demo();

 

         publicvoid run() {

                   while(true) {

                            synchronized(d) {

                                     if (tickets > 0){

                                               try{

                                                        Thread.sleep(50);

                                               }catch (InterruptedException e) {

                                                        //TODO Auto-generated catch block

                                                        e.printStackTrace();

                                               }

                                               System.out.println(getName()+ "正在出售第" + (tickets--)

                                                                 +"张票!");

                                     }

                            }

                   }

 

         }

}

 

class Demo {

 

}

 

3. public final int getPriority()返回线程的优先级。

线程的优先级有哪些?

默认优先级:5

java.lang.Thread

public static final int MAX_PRIORITY 10:最大优先级

优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性。

public static final int MIN_PRIORITY 1:最小优先级

public static final int NORM_PRIORITY 5:默认优先级

例:

public class ThreadProrityDemo {

         publicstatic void main(String[] args) {

                   //创建该线程的对象

                   MyPrioritymp1 = new MyPriority();

                   MyPrioritymp2 = new MyPriority();

                   MyPrioritymp3 = new MyPriority();

                   //获取线程的优先级

                   System.out.println(mp1.getPriority());//5默认

                   System.out.println(mp2.getPriority());//5默认

                   System.out.println(mp3.getPriority());//5默认

                   mp1.setName("Tom");

                   mp2.setName("Ammy");

                   mp3.setName("Lucy");

                   //给线程设置优先级

                   mp1.setPriority(10);

                   mp2.setPriority(1);

                   //启动线程

                   mp1.start();

                   mp2.start();

                   mp3.start();

         }

}

 

class MyPriority extends Thread {

         publicvoid run() {

                   for(int x = 0; x < 100; x++) {

                            System.out.println(getName()+ ":" + x);

                   }

         }

}

4. 线程中一些方法

public final void stop():强迫线程停止执行

public void interrupt()中断线程。 表示中断线程一种状态

join()

 yield()

stop()

setDeamon(boolean  on):(用的多)

 sleep():线程睡眠 (用的多)

wait():线程等待

方法:

1) public static void yield()暂停当前正在执行的线程对象,并执行其他线程。

暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权。

例:

public class YieldThreadDemo { 

     public static voidmain(String[] args) {             

              //创建线程类对象

              YieldThread yt1 =new YieldThread();

              YieldThread yt2 =new YieldThread();              

              //设置线程名称

              yt1.setName("Tom");

              yt2.setName("Anny");    

              //启动线程

              yt1.start();

              yt2.start();

     }

}

//自定义类

 class YieldThread extendsThread {

     public void run() {

              //yt1,yt2

              for(int x =0 ; x<100 ; x ++){

                       System.out.println(getName()+":"+x);

                       Thread.yield();

              }

     }

}

2) public final void join()

       throwsInterruptedException等待该线程终止。

例:

public class JoinDemo {       

     public static voidmain(String[] args) {

              JoinThread jt1 =new JoinThread();

              JoinThread jt2 =new JoinThread();

              JoinThread jt3 =new JoinThread();         

              //设置线程名称

              jt1.setName("Tom");

              jt2.setName("Anny");

              jt3.setName("Lucy");               

              //启动线程     

              jt1.start();                          

              //设置线程等待该线程终止该方法必须要启动线程

              try {

                       jt1.join();

              } catch(InterruptedException e) {

                       e.printStackTrace();

              }

             

              jt2.start();

              jt3.start();

     }

}

class JoinThread extends Thread {

     public void run() {

              for(int x = 0 ; x<100 ; x ++){

                       System.out.println(getName()+":"+x);

              }

     }

}

3) 线程停止:

       public final void stop():强迫线程停止执行

       public void interrupt()中断线程。

表示中断线程一种状态

例:

public class ThreadStopDemo {

         public static voidmain(String[] args) {

                   //创建线程类对象

                   ThreadStopts = new ThreadStop();

                   ts.start();

                   //如果3秒中不醒来,干掉它

                   try {

                            Thread.sleep(3000);

                            //强迫线程停止执行

                            ts.interrupt();//中断一种状态

                   } catch(InterruptedException e) {

                            e.printStackTrace();

                   }

         }

}

 

import java.util.Date;

public class ThreadStop extends Thread {

         public void run() {

                   System.out.println("开始执行了.."+newDate());

                   //睡眠10秒中

                   try {

                            Thread.sleep(10000);

                   } catch(InterruptedException e) {

                            System.out.println("线程终止了!");

                   }

                   System.out.println("结束执行"+newDate());

         }

4) public final void setDaemon(boolean on)  on指定true,就是设置守护线程...

将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。

jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就自动退出.

例:

public class ThreadDemaonDemo {

     public static voidmain(String[] args) {

              //创建线程类对象

              ThreadDeamon td1= new ThreadDeamon();

              ThreadDeamon td2= new ThreadDeamon();

              //设置线程名称

              td1.setName("Tom");

              td2.setName("Jeny");

              td1.setDaemon(true);

              td2.setDaemon(true);

              //启动线程

              td1.start();

              td2.start();

              Thread.currentThread().setName("Lucy");

              for(int x = 0 ; x<5 ; x++){

                       System.out.println(Thread.currentThread().getName()+":"+x);//设置主线程

              }

     }

}

class ThreadDeamon extends Thread {

              public void run(){

                       for(intx = 0 ; x <100 ; x ++){

                                 System.out.println(getName()+":"+x);

                       }

              }

}

5) 线程睡眠:

public static void sleep(long millis)

             throwsInterruptedException在指定的毫秒数内让当前正在执行的线程休眠暂停执行。

例:

public class ThreadSleepDemo {

     public static voidmain(String[] args) {

              //创建线程类对象

              ThreadSellp ts1 =new ThreadSellp();

              ThreadSellp ts2 =new ThreadSellp();

              ThreadSellp ts3 =new ThreadSellp();

              //设置线程名称

              ts1.setName("线程1");

              ts2.setName("线程2");

              ts3.setName("线程3");

              //启动线程

              ts1.start();

              ts2.start();

              ts3.start();

     }

}

 

import java.util.Date;

public class ThreadSellp extends Thread {

     public void run() {

              //ts1,ts2,ts3

              for(int x = 0 ; x<100 ; x ++){

                       System.out.println(getName()+":"+x+",日期:"+newDate());

                       //睡眠1秒中:2000毫秒

                       try {

                                 Thread.sleep(2000);//此方法本身就抛出一个异常

                       } catch(InterruptedException e) {

                                 e.printStackTrace();

                       }

              }

     }

}

6. 线程安全的类有哪些?

     Vector

StringBuffer

Hasttable

public class ThreadDemo {

     public static voidmain(String[] args) {

              //1)集合里面的Vector集合

              Vector<String>v = new Vector<String>();

              //2)字符串缓冲区

              StringBuffer sb =new StringBuffer("Hello");

              //3)Map集合中的子实现类:Hashtable

              Hashtable<String,String> hm = new Hashtable<String,String>();

              //从集合中来看,vector集合是一个安全的类,实际开发也不怎么用它

              //Collections:针对集合操作的工具类

              //public static<T> List<T> synchronizedList(List<T> list)返回指定列表支持的同步(线程安全的)列表

              ArrayList list =new ArrayList();

              List l =Collections.synchronizedList(list); 

     }

}

 

Day21

1. 使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况Jdk5以后Java提供了一个更具体的锁对象:Lock。

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作

Lock是一个接口,所以它在使用的是 ReentrantLock子实现类

public void lock()获取锁。

public void unlock()试图释放此锁

没有抛出具体的异常,需要捕获异常

捕获异常标准格式:try...catch...finally

变形格式:try...finally...

例:

public class SellTicketsDemo {    

     public static voidmain(String[] args) {             

              //创建资源对象

              SellTickets st =new SellTickets();   

              //创建线程对象

              Thread t1 = newThread(st, "窗口1");

              Thread t2 = newThread(st, "窗口2");

              Thread t3 = newThread(st, "窗口3");           

              //启动线程

              t1.start();

              t2.start();

              t3.start();

     }

}

 

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class SellTickets implements Runnable {

     private int tickets = 100;

     // 定义一个具体锁对象

     private Lock lock = newReentrantLock();

     // 捕获异常标准格式:try...catch...finally

     // 变形格式:try...finally...

     public void run() {

              // 假设电影院一直有票

              while (true) {

                       try {

                                 //获取锁

                                 lock.lock();

                                 if(tickets > 0) {

                                          //加入延迟操作

                                          try{

                                                   Thread.sleep(50);

                                          }catch (InterruptedException e) {

                                                   e.printStackTrace();

                                          }

                                          System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票");

                                 }

                       }finally {

                                 //释放锁对象

                                 lock.unlock();

                       }

              }

     }

}

2. 使用同步机制可以解决多线程的安全问题,但是自身也会有弊端:

1)同步---->执行效率低(每一个线程在抢占到CPU的执行权,会去将(门)关闭,别的线程进不来)

2)容易出现死锁现象

死锁线程:两个或者两个以上的线程出现了互相等待的情况,就会出现死锁。

例:

中国人和美国人吃饭

中国人:一双筷子

美国人:一把刀,一把叉

现在:

中国人:一根筷子和一把刀

美国人:一根筷子和一把叉

public class DeadLockDemo {

public static void main(String[] args) {                  

              //创建线程类对象

              DeadLock dl1 =new DeadLock(true);

              DeadLock dl2 =new DeadLock(false);             

              //启动线程

              dl1.start();

              dl2.start();

     }       

// 运行时可能出现的情况:

//  if objA   else objB

//  else objB if objA

// 理想状态:

// if objA

// if objB

// else objB

// else objA

}

 

public class DeadLock extends Thread {

     // 定义一个成员变量

     private boolean flag;

     public DeadLock(booleanflag) {

              this.flag = flag;

     }

     public void run() {

              // dl1,dl2线程

              if (flag) {

                       synchronized(MyLock.objA) {

                                 System.out.println("ifobjA");

                                 synchronized(MyLock.objB) {

                                          System.out.println("ifobjB");

                                 }

                       } // 代码执行完毕,objA锁相当于才能被释放掉

              } else {

                       // dl2

                       synchronized(MyLock.objB) {

                                 System.out.println("elseobjB");

                                 synchronized(MyLock.objA) {

                                          System.out.println("elseobjA");

                                 }

                       }

              }

     }

}

class MyLock {

     // 创建两把锁对象

     public static final ObjectobjA = new Object();

     public static final ObjectobjB = new Object();

}

3. 分析:

提供:资源对象:Student类:提供一些成员变量:姓名和年龄

生产者线程:SetThread类:生产一些学生数据(设置学生数据)

消费者线程:GetThread类:输出学生数据

测试类:StudentDemo类,实现多线程环境

操作:

使用刚才的这几个类:模拟生产消费者模式,生产者SetThread产生学生数据,而GetThread消费者线程输出学生数据,发现一个问题, 问题:输出学生数据的时候,是null   0。

对于每一个线程都在创建自己的学生对象,两个线程操作的两个对象而不是同一个对象,所以应该解决:将学生对象成员变量,然后通过构造方法进行传递,在测试类中,创建学生对象(同一个资源对象)让多个线程对这个学生对象进行操作。

public  class  StudentDemo1 {

     public static voidmain(String[] args) {

              // 创建一个学生对象

              Student  s = new Student();

              // 创建自定义线程类对象

              SetThread  st = new SetThread(s);

              GetThread  gt = new GetThread(s);

              // 创建线程类对象

              Thread t1 = newThread(st);

              Thread t2 = newThread(gt);

              // 启动线程

              t1.start();

              t2.start();

     }

}

 

//学生类

class  Student {

     String  name;

     int  age;

}

 

// 生产者线程

class SetThread implements Runnable {

     private  Student s;

     public  SetThread(Student s) {

              this.s = s;

     }

     public void run() {

              // 设置学生数据

              s.name ="Tom";

              s.age = 23;

     }

}

 

// 消费者线程

class GetThread implements Runnable {

     private Student s;

//构造方法

     public GetThread(Students) {

              this.s = s;

     }

     public void run() {

              // 输出语句

              System.out.println(s.name+ "    " + s.age);

     }

}

 

改进:为了数据多并且效果更明显,加入循环语句进行操作,给生产者线程和消费者线程分别加入循环语句(while循环)

public class StudentDemo2 {

     public static voidmain(String[] args) {

              // 创建一个学生对象

              Student1 s = newStudent1();

              // 创建自定义线程类对象

              SetThread1 st =new SetThread1(s);

              GetThread1 gt =new GetThread1(s);

              // 创建线程类对象

              Thread t1 = newThread(st);

              Thread t2 = newThread(gt);

              // 启动线程

              t1.start();

              t2.start();

     }

}

 

//学生类

class Student1 {

     String name;

     int age;

}

 

// 生产者线程

class SetThread1 implements Runnable {

     private Student1 s;

     public SetThread1(Student1s) {

              this.s = s;

     }

     private int x = 0;

     public void run() {

              while (true) {

                       // 同步机制进行操作

                       synchronized(s) {

                                 if(x % 2 == 0) {

                                          //x = 0

                                          //设置学生数据

                                          s.name= "Anny";

                                          s.age= 33;

                                 }else {

                                          //设置学生数据

                                          s.name= "Lucy";

                                          s.age= 22;

                                 }

                                 x++;

                       }

              }

     }

}

 

// 消费者线程

class GetThread1 implements Runnable {

     private Student1 s;

     public GetThread1(Student1s) {

              this.s = s;

     }

     public void run() {

              while (true) {

                       synchronized(s) {

                                 //输出语句

                                 System.out.println(s.name+ "    " + s.age);

                       }

              }

     }

}

改进之后出现两个问题:

1)同一个数据打印多次 //CPU一点点时间片足够执行很多次。

2)并且年龄和姓名不符合线程的随机性导致的。

优化改进之后,这些问题就说明当前多线程有安全问题: 多线程安全问题的标准: 1)是否是多线程环境

2)是否有共享数据

3)是否有多条语句对共享数据操作

当前是多线程环境,有共享数据,有多条语句对共享数据:s.name,s.age

使用同步机制来解决这个问题:将多条语句对共享数据进包装

使用同步机制去解决线程的安全问题,但是又有一个新的问题: 测试的时候,数据打印一打一大片,体验不好。

需求:让这个数据依次进行打印控制台,要使用这种方式去解决,利用Java等待唤醒机制。

public class StudentDemo3 {

     public static voidmain(String[] args) {

              // 创建学生对象

              Student2 s = newStudent2();

              SetThread2 st =new SetThread2(s);

              GetThread2 gt =new GetThread2(s);

              // 创建线程类对象

              Thread t1 = newThread(st);

              Thread t2 = newThread(gt);

              // 启动线程

              t1.start();

              t2.start();

     }

}

 

class Student2 {

     String name;

     int age;

     // 声明一个变量

     boolean flag; // 默认没有数据,如果true,则说明有数据

}

 

// 生产者线程

class SetThread2 implements Runnable {

     private Student2 s;

     public SetThread2(Student2s) {

              this.s = s;

     }

     private int x = 0;

     public void run() {

              while (true) {

                       // 同步机制进行操作

                       synchronized(s) {

                                 //判断有没有数据

                                 if(s.flag) {

                                          //处于等待状态

                                          try{

                                                   s.wait();//阻塞式方法,立即释放锁

                                          }catch (InterruptedException e) {

                                                   e.printStackTrace();

                                          }

                                 }

                                 if(x % 2 == 0) {

                                          //x = 0

                                          //设置学生数据

                                          s.name= "Jeny";

                                          s.age= 33;

                                 }else {

                                          //设置学生数据

                                          s.name= "Lucy";

                                          s.age= 27;

                                 }

                                 x++;

                                 //修改标记

                                 s.flag= true;// 有数据

                                 //通知t2:消费者线程来消费数据

                                 s.notify();//唤醒等待这种状态

                       }

              }

     }

}

 

// 消费者线程

class GetThread2 implements Runnable {

     private Student2 s;

     public GetThread2(Student2s) {

              this.s = s;

     }

     public void run() {

              while (true) {

                       synchronized(s) {

                                 //判断有没有数据

                                 if(!s.flag) {

                                          try{

                                                   s.wait();//调用的时候,会立即释放锁

                                          }catch (InterruptedException e) {

                                                   e.printStackTrace();

                                          }

                                 }

                                 //输出语句

                                 System.out.println(s.name+ "    " + s.age);

                                 //修改标记

                                 s.flag= false;// 消费者线程

                                 //通知对方(t1线程),消费者线程没有数据类,赶紧来消费

                                s.notify();// 唤醒t1线程

                       }

              }

     }

}

再次改进:(最终版代码)

现在将资源对象Student中的成员变量私有化

并且给当前类中提供两个方法,同步方法

在两个线程:生产者线程和消费者中线程,注意调用这两个方法就可以了

public class StudentDemo4 {       

     public static voidmain(String[] args) {             

              //创建一个资源对象

              Student3 s = newStudent3();         

              //创建资源对象

              SetThread3 st =new SetThread3(s);

              GetThread3 gt =new GetThread3(s);            

              //创建线程类对象

              Thread t1 = newThread(st);

              Thread t2 = newThread(gt);          

              //分别启动线程              

              t1.start();

              t2.start();                 

     }

}

 

class Student3 {  

     private String name;

     private int age;

     //声明一个变量

     private boolean flag; //默认没有数据,如果true,则说明有数据

     public synchronized voidset(String name, int age) {

              // 同步机制进行操作

              // 判断有没有数据

              if (this.flag) {

                       // 处于等待状态

                       try {

                                 this.wait();//阻塞式方法,立即释放锁 notify notifyAll();

                       } catch(InterruptedException e) {

                                 e.printStackTrace();

                       }

              }                

              //设置学生数据

              this.name = name;

              this.age = age;                 

              //修改标记

              this.flag = true;//有数据

              //通知t2:消费者线程来消费数据

              this.notify() ;//唤醒等待这种状态

     }       

     public synchronized voidget(){

                       if(!this.flag){

                                 try{

                                          this.wait();//调用的时候,会立即释放锁

                                 }catch (InterruptedException e) {

                                          e.printStackTrace();

                                 }

                       }

                       //输出语句

                       System.out.println(this.name+"   "+this.age);                      

                       //修改标记

                       this.flag= false ;//消费者线程

                       //通知对方(t1线程),消费者线程没有数据类,赶紧来消费

                       this.notify();//唤醒t1线程

     }       

}

 

//生产者线程

class SetThread3 implements Runnable {  

     private Student3 s;

     public SetThread3(Student3s){

              this.s = s;

     }       

     private int x = 0;

     public void run() {

              while(true){

                       if(x %2==0){

                                 s.set("Anny",33);

                       }else{

                                 s.set("Lucy",22);

                       }

                       x ++;

              }                

     }

}

 

//消费者线程

class GetThread3 implements Runnable { 

     private Student3 s;

     public GetThread3(Student3s){

              this.s = s;

     }

     public void run() {

              while (true) {

                       // 调用方法

                       s.get();

              }

     }

}

 

4. 线程组表示一个线程的集合:Java允许一个线程中有多个线程

public final ThreadGroup getThreadGroup()返回该线程所属的线程组

public class ThreadGroupDemo {

     public static voidmain(String[] args) {

//           method1();               

              method2();

     }                

     //给每一个子线程可以设置线程名称

     private static voidmethod2() {

              //设置线程组名称

//           public ThreadGroup(Stringname)构造一个新线程组

              ThreadGroup tg =new ThreadGroup("新的线程组");  

              //创建资源对象

              MyRunnable my =new MyRunnable();

              //创建线程类对象,将线程组对象作为参数进行传递,使用Thread类的构造方法

              //publicThread(ThreadGroup group,Runnable target ,String name){}

              Thread t1 = newThread(tg, my, "线程1");//打印:新的线程组

              Thread t2 = newThread(tg, my, "线程2");//打印:新的线程组

//           public finalThreadGroup getThreadGroup()返回该线程所属的线程组

              ThreadGroup tg1 =t1.getThreadGroup();

              ThreadGroup tg2 =t2.getThreadGroup();

              //获取打印子线程名

              System.out.println(tg1.getName());

              System.out.println(tg2.getName());                

              tg.setDaemon(true);//将线程组中的所有的线程都设置为守护线程(后台线程)

     }

     //获取子线程的默认线程组名

     private static voidmethod1() {

              //创建资源对象

              MyRunnable my =new MyRunnable();

              //创建两个线程类对象

              Thread t1 = newThread(my);

              Thread t2 = newThread(my);          

              //获取线程组对象

//           public finalThreadGroup getThreadGroup()返回该线程所属的线程组

              ThreadGroup tg1 =t1.getThreadGroup();

              ThreadGroup tg2 =t2.getThreadGroup();               

//           public finalThreadGroup getName()获取t1,和t2线程所在的线程名称

              String name1 = tg1.getName();

              String name2 =tg2.getName();      

              //子线程默认的线程组名称:main线程

              System.out.println(name1);//main

              System.out.println(name2);//main

              //所有的线程它的默认线程组名称就是main

              System.out.println(Thread.currentThread().getThreadGroup().getName());//main              

     }

}

 

public class MyRunnable implements Runnable {

     public void run() {

              for(int x = 0 ; x<100 ; x ++){

                       System.out.println(Thread.currentThread().getName()+":"+x);

              }

     }

}

5. JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法:

public static ExecutorService newFixedThreadPool(int nThreads)

Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程。

这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法:

ExecutorsService :接口中的方法

Future<?> submit(Runnable task)<T> Future<T>submit(Callable<T> task)

线程池的好处:节约成本,很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用。

例:

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ExecutorsDemo {

     public static voidmain(String[] args) {

              // 创建线程池对象,使用Executors工厂类

              // public staticExecutorService newFixedThreadPool(int nThreads)

              ExecutorServicepool = Executors.newFixedThreadPool(2);

              // 使用ExecutorService(跟踪多个异步任务)一些方法

              // 使用submit(Runnabletarget):提交多个任务

              pool.submit(newMyRunnable());

              pool.submit(newMyRunnable());

              // 结束线程池

              pool.shutdown();

     }

}

public class MyRunnable implements Runnable {

     @Override

     public void run() {

              //for循环

              for(int x = 0 ; x< 100 ; x ++){

                       System.out.println(Thread.currentThread().getName()+":"+x);

              }

     }

}

6. 线程求和

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

public class CallableDemo {         

     public static voidmain(String[] args) throws InterruptedException, ExecutionException {

              //创建线程池对象,利用工厂类:Executors

              ExecutorServiceThreadPool = Executors.newFixedThreadPool(2) ;                

              //提交2异步任务,分别计算1-100,1-200之间的和

              Future<Integer>f1 = ThreadPool.submit(new MyCallable(100)) ;

              Future<Integer>f2 = ThreadPool.submit(new MyCallable(200)) ;         

              //分别调用Future接口中  get()方法,返回具体的结果

              Integer v1 =f1.get() ;

              Integer v2 =f2.get() ;               

              //输出结果

              System.out.println("v1:"+v1);

              System.out.println("v2:"+v2);

     }

}

 

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {   

     private int number ;

     public MyCallable(intnumber){

              this.number =number ;

     }

     public Integer call()throws Exception {

              //定义最终结果变量

              int sum = 0 ;

              for(int x = 1 ; x<=number;  x ++ ){

                       sum += x;

              }

              return sum;

     }       

}

7. JavaSe中的定时器:

 Timer:

常用的几个方法:

public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务

public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务

public void schedule(TimerTask task, long delay, long period)在多少毫秒后,执行任务,并且每个多少毫秒重复执行

public void cancel()终止此计时器,丢弃所有当前已安排的任务

例:

import java.util.Timer;

import java.util.TimerTask;

public class TimerDemo {

     public static voidmain(String[] args) {

              // public Timer()创建一个新计时器。

              Timer t = newTimer();

              // TimerTask:需要被执行的任务类是一个抽象类,所以不能直接实例化

              t.schedule(newMyTask(t), 3000);

     }

}

class MyTask extends TimerTask {

     private Timer t;

     public MyTask() {

     }

     public MyTask(Timer t) {

              this.t = t;

     }

     public void run() {

              System.out.println("你弱爆了!!!");

              t.cancel();// 取消任务

     }

}

8. 在指定的时间删除的指定目录

import java.io.File;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

public class DeleteDemo {

     public static voidmain(String[] args) throws ParseException {                

              //创建一个定时器对象

              Timer t = new  Timer() ;                  

              //public voidschedule(TimerTask task,Date time)安排在指定的时间执行指定的任务              

              //定义日期格式

              String dateStr ="2017-12-5 21:21:00" ;

              //解析成Date对象

              //创建SimpleDateFormat对象

              SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;

              //解析方法

              Date date = sdf.parse(dateStr) ;

              //调用定时器的这个在规定时间内执行某个任务的方法

              t.schedule(newDeleteFolder(), date) ;

     }

}

class DeleteFolder extends TimerTask{

     public void run() {

              //封装当前项目下的这个demo文件

              File srcFolder =new File("Demo") ;

              deleteFolder(srcFolder);

     }       

     //递归删除

     private voiddeleteFolder(File srcFolder) {

              //获取当前srcFolder下面的所有的文件以及文件夹的File数组

              File[] fileArray= srcFolder.listFiles();

              //对该对象非空判断

              if(fileArray!=null){

                       //增强for遍历

                       for(Filefile :fileArray){

                                 //继续判断file对象是否是文件夹

                                 if(file.isDirectory()){

                                          //回到删除目录的方法

                                          deleteFolder(file);

                                 }else{

                                          //不是目录,是文件,直接删除

                                          System.out.println(file.getName()+"---"+file.delete());

                                 }

                       }

                       System.out.println(srcFolder.getName()+"----"+srcFolder.delete());

              }

     }

}

9. 多线程中匿名内部类的方式

     格式:

new 类名(具体类,抽象类),接口(){

              重写/实现方法;

    }

匿名内部类的本质:继承了该类或者是实现该接口的子类对象。

例:

public class ThreadDemo2 {        

     public static voidmain(String[] args) {             

              //继承自Thread类

              new Thread(){

                       publicvoid run() {

                                 //for循环

                                 for(intx = 0 ; x <100 ; x ++){

                                          System.out.println(Thread.currentThread().getName()+":"+x);

                                 }

                       }

              }.start() ;//启动线程       

              //Runnable接口的方式

              new Thread(newRunnable() {                  

                       publicvoid run() {

                                 //for循环

                                 for(intx = 0 ; x < 100 ; x ++){

                                          System.out.println(Thread.currentThread().getName()+":"+x);

                                 }

                       }

              }).start() ;         

    

              new Thread(newRunnable() {                  

                       publicvoid run() {

                                 for(intx = 0 ; x <100 ; x ++){

                                          System.out.println("hello"+x);

                                 }

                       }

              }){

                       publicvoid run() {

                                 for(intx = 0 ; x <100 ; x ++){

                                          System.out.println("world  "+x);

                                 }

                       }

              }.start();

     }

}

原创粉丝点击