开始整理线程之前,之前有个命令忘记整理了,先整理一下jar命令的使用
Jar包
其实可以理解是java的压缩包
方便使用,只要在classpath设置jar路径即可
数据库驱动,ssh框架等都是以jar包体现的
打包方式一:将指定的class文件打入到jar包中
jar cvf xxx.jar Xxx.class yyy.class
打包方式二:将某个目录下的所有文件打入到jar包中
jar cvf xxx.jar -C xxx/.
查看jar文件:
jar -tf xxx.jar
运行jar包中的类:
java -cp xxx.jar xx.xx.xx(完整的类名)
常用的jar命令参数:
c:创建压缩文件
f:指定存档名称
v:显示详细信息
m:加入自定义清单
指定清单文件(xxx.jar/META-INF/MNIFEST.MF)的入口类
jar cvfe classess.jar com.zhaofan.PackagDemo1 classes/.
这样我们就可以通过java -jar xxx.jar直接执行
线程
进程:运行时概念,运行的应用程序
线程:应用程序内部并发执行的代码段,共享内存
这里几个关键词
yield: 放弃cpu抢占权
join:等待指定的线程执行完
sleep:静态方法,让线程休眠毫秒数
daemo:守护线程
最简单的线程代码:
package study_java.ex9; public class ThreadDemo1 { public static void main(String[] args){ Mythread t1 = new Mythread(); t1.start(); } } class Mythread extends Thread{ public void run(){ while (true){ System.out.println("MyThread"); } } }
join的一个简单实用例子:
package study_java.ex9; public class ThreadDemo2 { public static void main(String[] args){ Player p1 = new Player("aa",5000); Player p2 = new Player("bb",8000); Player p3 = new Player("cc",2000); Player p4 = new Player("dd",3000); p1.start(); p2.start(); p3.start(); p4.start(); try{ p1.join(); p2.join(); p3.join(); p3.join(); } catch (Exception e){ } System.out.println("人到了,开始玩游戏"); } } class Player extends Thread{ private String name; private int time; public Player(String name, int time){ this.name = name; this.time = time; } public void run(){ System.out.println("玩家:"+name + "出发了"); try{ Thread.sleep(time); } catch (Exception e){ } System.out.println("玩家:"+name + "到了"); } }
守护线程的一个使用例子
package study_java.ex9; import java.util.Date; public class ThraedDemo3 { public static void main(String[] args){ Room r1 = new Room("no1",15000); Waiter w1 = new Waiter(); //w1.setDaemon(true); 设置守护线程 r1.start(); w1.start(); } } class Room extends Thread{ private String no; private int time; public Room(String no, int time){ this.no = no; this.time = time; } public void run(){ System.out.println("no" + "号房间正在唱歌"); try{ Thread.sleep(time); } catch (Exception e){ } System.out.println("no" + "买单"); } } class Waiter extends Thread{ public Waiter(){ this.setDaemon(true); } public void run(){ while (true){ System.out.println(new java.util.Date()); try{ Thread.sleep(1000); } catch (Exception e){ } } } }
任何一个对象都可以是锁,信号灯,其实就是一个参照物
一个锁的代码例子:
package study_java.ex9; public class ThreadDemo4 { public static void main(String[] args){ Saler s1 = new Saler("a1"); Saler s2 = new Saler("a2"); s1.start(); s2.start(); } } class Saler extends Thread{ // 锁 static Object lock = new Object(); static int tickts = 100; private String name; public Saler(String name){ this.name = name; } public void run(){ while (true){ int tick = getTickts(); if (tick > 0){ System.out.println(name+":"+ tick); } else { return; } } } // 取票 public int getTickts(){ synchronized (lock){ int currTicket = tickts; tickts --; return currTicket; } } }
还有一种方法是:
public static synchronized int getTickts(){ int currTicket = tickts; tickts --; return currTicket; }
这样也能实现锁的机制,但是注意这里必须是static
我们整理一个新的写法,把票池单独写出来
public class ThreadDemo2 { public static void main(String[] args){ TicketPool pool = new TicketPool(); Saler s1 = new Saler("s1",pool); Saler s2 = new Saler("s2",pool); s1.start(); s2.start(); } } // 票池 class TicketPool { private int tickets = 100; // 从票池取票 public synchronized int getTickets(){ int ticket = tickets; tickets -= 1; return ticket; } } // 售票员 class Saler extends Thread{ private TicketPool pool = null; private String name; public Saler(String name, TicketPool tp){ this.name = name; this.pool = tp; } public void run(){ while (true){ int no = pool.getTickets(); if (no > 0 ){ System.out.println(name + ":" + no); } else { return; } } } }
两个小的练习熟悉上面知识点的使用:
车过山洞的问题,山洞同时只允许一个车通过,现在有多辆车,不同的车通过的时间不同,代码实现如下:
package study_java.ex11; public class CarCave { public static void main(String[] args){ Cave cave = new Cave(); Car car1 = new Car(cave,10000,"奥迪"); Car car2 = new Car(cave,8000,"奔驰"); Car car3 = new Car(cave,6000,"宝马"); Car car4 = new Car(cave,2000,"悍马"); car1.start(); car2.start(); car3.start(); car4.start(); } } class Cave{ public synchronized void crossCar(Car car){ try{ System.out.println(car.name+":开始过山洞了"); Thread.sleep(car.time); System.out.println(car.name+":开始出山洞了"); } catch (Exception e){ } } } class Car extends Thread{ public Cave cave; public int time; public String name; public Car(Cave cave ,int time,String name){ this.cave = cave; this.time = time; this.name = name; } public void run(){ cave.crossCar(this); } }
第二个小练习是我们经常遇到的场景,取票问题,现在有一个取票机,但是有五十个人要取票,实现代码如下:
package study_java.ex11; public class TicketDemo1 { public static void main(String[] args){ TicketMachine m = new TicketMachine(); for (int i=0;i<50;i++){ new Person(m,"tom"+i).start(); } } } // 取票机 class TicketMachine{ private int ticketNo = 1; // 打印票号 public synchronized int printTicktNo(){ int currTicketNo = ticketNo; ticketNo ++; return currTicketNo; } } class Person extends Thread{ private TicketMachine m; private String name; public Person(TicketMachine m,String name) { this.m = m; this.name = name; } public void run(){ int no = m.printTicktNo(); System.out.println(name+ ":" + no); } }
生产者消费者模型
通过上面的知识点,写一个生产者好消费者模型
package study_java.ex11; import java.util.LinkedList; import java.util.List; public class PCDemo1 { public static void main(String[] args){ MyList myList = new MyList(); Productor p = new Productor(myList); Consumer c = new Consumer(myList); Consumer c2 = new Consumer(myList); Consumer c3 = new Consumer(myList); p.start(); c.start(); c2.start(); c3.start(); } } class MyList{ private int Max = 100; private List<Integer> list = new LinkedList<Integer>(); public void addLast(Integer i){ while (true){ synchronized (list){ if (list.size() < Max){ list.add(i); return; } } } } public Integer removeFirst(){ while (true){ synchronized (list){ if(!list.isEmpty()){ return list.remove(0); } } } } } class Productor extends Thread{ private MyList myList; public Productor(MyList myList){ this.myList = myList; } public void run(){ int i = 1; while (true){ myList.addLast(new Integer(i)); System.out.println("生产者生产了"+i+"号"); i++; } } } class Consumer extends Thread{ private MyList myList; public Consumer(MyList myList){ this.myList = myList; } public void run(){ while (true){ int no = myList.removeFirst(); System.out.println("消费者消费了"+no+"号"); } } }
生产者消费者而改进版本:
package study_java.ex11; import java.util.LinkedList; import java.util.List; public class PCDemo5 { public static void main(String[] args){ Pool pool = new Pool(); Producter p1 = new Producter(pool); Consumer c1 = new Consumer(pool); p1.start(); c1.start(); } } class Pool{ private List<Integer> list = new LinkedList<Integer>(); private int Max = 100; public void addLast(int n){ synchronized (this){ while (list.size() >= Max){ try{ this.wait(); } catch (Exception e){ e.printStackTrace(); } } list.add(new Integer(n)); this.notifyAll(); } } public int remove(){ synchronized (this){ while (list.size() == 0){ try{ this.wait(); } catch (Exception e){ e.printStackTrace(); } } int no = list.remove(0); this.notifyAll(); return no; } } } // 生产者 class Producter extends Thread{ private Pool pool; static int i = 1; public Producter(Pool pool){ this.pool = pool; } public void run(){ while (true){ pool.addLast(i++); System.out.println("生产者生产了"+i+"号"); } } } // 消费者 class Consumer extends Thread{ private Pool pool; public Consumer(Pool pool){ this.pool = pool; } public void run(){ while (true){ int no = pool.remove(); System.out.println("消费者消费了"+no+"号"); } } }
wait():让当前线程进入到锁对象的等待队列里,同时释放锁旗标。这个方法是当前锁对象的方法
wait这里还可以添加参数wait(int n) :等待指定的时间片,等待队列中的线程最多等待n毫秒
notify():这个方法是当前锁对象的方法,注意这里并不会释放锁
notifyAll():通知等待队列中的所有线程都可以抢占cpu运行,通知需要获得对象的监控权
sleep:当前CPU的抢占权,和锁对象的监控权无关。
Thread.currentThread().getName():获取当前线程名字
Thread.currentThread().setName():设置当前线程名字
priority:1-10从低到高,默认是5
Thread.currentThread().getPriority():设置当前线程优先级
线程状态:
BLOCKED: 阻塞
NEW:新建
RUNNABL:执行
TERMINATED:已经终止
TIMED_WAITING:限时等待
WAITING:等待
创建一个线程的另外一种方式:
实现Runnable接口
1. 子类覆盖接口中的run方法
2. 通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数
3. Thread类对象调用start方法开启线程
代码例子如下:
package study_java.ex11; public class RunnableDemo1 { public static void main(String[] args){ MyRunnabl m = new MyRunnabl(); new Thread(m).start(); } } class MyRunnabl implements Runnable{ public void run(){ System.out.println("hello world"); } }
同步(synchronized)
synchronized(对象)
{
需要同步的代码
}
同步的特点:
同步的前提是:
需要两个或者两个以上的线程
多个线程使用的同一个锁
同步的弊端:
当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的额运行效率