Java基础9-死锁;String;编码
昨日内容回顾
-
死锁案例
class DeadLock{ public static void main(String[] args){ Pool pool = new Pool(); Producer p1 = new Producer("p1",pool); Consumer c1 = new Consumer("c1",pool); Consumer c2 = new Consumer("c2",pool); p1.setName("p1"); c1.setName("c1"); c2.setName("c2"); p1.start(); c1.start(); c2.start(); } } class Producer extends Thread{ String name; Pool pool; public Producer(String name, Pool pool){ this.name = name; this.pool = pool; } public void run(){ while(true){ pool.add(); } } } class Consumer extends Thread{ String name; Pool pool; public Consumer(String name, Pool pool){ this.name = name; this.pool = pool; } public void run(){ while(true){ pool.remove(); } } } class Pool{ private int MAX=1; private int count; public synchronized void add(){ String name = Thread.currentThread().getName(); while(count>=MAX){ try{ System.out.println(name+":"+"wait()"); this.wait(); } catch(Exception e){} } System.out.println(name+":"+(++count)); System.out.println(name+":"+"notify()"); this.notify(); } public synchronized void remove(){ String name = Thread.currentThread().getName(); while(count<MAX){ try{ System.out.println(name+":"+"wait()"); this.wait(); } catch(Exception e){} } System.out.println(name+":"+(--count)); System.out.println(name+":"+"notify()"); this.notify(); } }
-
同步方法中,wait()与notify()执行流程
class WaitDemo{ public static void main(String[] args){ Cave cave = new Cave(); Car c1 = new Car("奔驰",cave); Car c2 = new Car("宝马",cave); c1.start(); c2.start(); try{ Thread.sleep(5000); synchronized(cave){ cave.notifyAll(); } } catch(Exception e){} } } class Cave{ } class Car extends Thread{ private String name; private Cave cave; public Car(String name, Cave cave){ this.name = name; this.cave = cave; } public void run(){ synchronized(cave){ System.out.println(name+"进洞了!"); try{ cave.wait(); } catch(Exception e){} System.out.println(name+"wait后代码"); } } }
-
设置线程优先级
class WaitDemo{ public static void main(String[] args){ Cave cave = new Cave(); Car c1 = new Car("奔驰",cave); Car c2 = new Car("宝马",cave); //设置线程优先级 Thread.currentThread().setPriority(Thread.MAX_PRIORITY); c1.setPriority(Thread.MIN_PRIORITY); c2.setPriority(Thread.NORM_PRIORITY); System.out.println("c1.priority:"+c1.getPriority()); System.out.println("c2.priority:"+c2.getPriority()); System.out.println("main.prio : " +Thread.currentThread().getPriority()); c1.start(); c2.start(); try{ Thread.sleep(5000); synchronized(cave){ cave.notifyAll(); } } catch(Exception e){} } } class Cave{ } class Car extends Thread{ private String name; private Cave cave; public Car(String name, Cave cave){ this.name = name; this.cave = cave; } public void run(){ synchronized(cave){ System.out.println(name+"进洞了!"); try{ cave.wait(); } catch(Exception e){} System.out.println(name+"wait后代码"); } } }
作业讲解
-
一共100个馒头,40个工人,每个工人最多能吃3个馒头,使用多线程输出所有工人吃馒头的情况
class ThreadDemo{ public static void main(String[] args){ Basket basket = new Basket(); Worker w[] = new Worker[40]; for(int i=0;i<40;i++){ w[i] = new Worker("worker-"+i,basket); } for(int i=0;i<40;i++){ w[i].start(); } } } //放馒头的篮子 class Basket{ private int No = 100; //取馒头 public int getNo(){ if(No<=0){ return -1; } else{ return No--; } } } //工人线程类 class Worker extends Thread{ private static Basket basket; private String name; private int sumNo=0;//总共吃的馒头数 public Worker(String name,Basket basket){ this.basket = basket; this.name = name; } public void run(){ while(true){ synchronized(basket){ if(sumNo>=3){ return; } int no = basket.getNo(); if(no==-1){ return; } else{ sumNo++; System.out.println(name+"吃了第"+no+"个馒头,共吃了"+sumNo+"个馒头"); } } Thread.yield(); } } }
-
5辆汽车过隧道,隧道一次只能通过一辆汽车。每辆汽车通过时间不固定,
机动车通过时间3秒,三轮车通过时间5秒,畜力车通过时间10秒,5辆车分别是2辆机动车,2辆畜力车,1辆三轮车,通过多线程模拟通过隧道的情况。提示:Car ThreeCar CowCarclass ThreadDemo{ public static void main(String[] args){ Cave cave = new Cave(); new Car(cave,"汽车1",3).start(); new Car(cave,"汽车2",3).start(); new ThreeCar(cave,"三轮车",5).start(); new CowCar(cave,"畜力车1",10).start(); new CowCar(cave,"畜力车2",10).start(); } } //隧道,山洞 class Cave{ } //机动车线程类 class Car extends Thread{ private Cave cave; private int sec; private String name; public Car(Cave cave, String name, int sec){ this.cave = cave; this.name = name; this.sec = sec; } public void run(){ synchronized(cave){ System.out.println(name+"进洞了!"+new java.util.Date()); try{ Thread.sleep(sec*1000); } catch(Exception e){} System.out.println(name+"出洞了!"+new java.util.Date()); } } } //三轮车线程类 class ThreeCar extends Thread{ private Cave cave; private int sec; private String name; public ThreeCar(Cave cave, String name, int sec){ this.cave = cave; this.name = name; this.sec = sec; } public void run(){ synchronized(cave){ System.out.println(name+"进洞了!"+new java.util.Date()); try{ Thread.sleep(sec*1000); } catch(Exception e){} System.out.println(name+"出洞了!"+new java.util.Date()); } } } //畜力车线程类 class CowCar extends Thread{ private Cave cave; private int sec; private String name; public CowCar(Cave cave, String name, int sec){ this.cave = cave; this.name = name; this.sec = sec; } public void run(){ synchronized(cave){ System.out.println(name+"进洞了!"+new java.util.Date()); try{ Thread.sleep(sec*1000); } catch(Exception e){} System.out.println(name+"出洞了!"+new java.util.Date()); } } }
-
用多线程模拟蜜蜂和熊的关系
蜜蜂是生产者,熊是消费者,蜜蜂生产蜂蜜是累加的过程,熊吃蜂蜜是批量(满20吃掉)的过程,生产者和消费者之间使用通知方式告知对方,注意不能出现死锁现象。
100只蜜蜂,每次生产的蜂蜜是1
熊吃蜂蜜是20(批量的情况)class ThreadDemo{ public static void main(String[] args){ Pot pot = new Pot(); for(int i=1;i<=100;i++){ new Bee("蜜蜂-"+i,pot).start(); } new Bear("熊大",pot).start(); new Bear("熊二",pot).start(); } } //蜜罐 class Pot{ private int MAX = 20;//最大值 private int count;//当前量 //添加蜂蜜,+1 public synchronized int add(){ while(count >= MAX){//若是if则下次进入线程,就不再去判断,存在问题 try{ this.notifyAll(); this.wait(); } catch(Exception e){ e.printStackTrace(); } } return ++count; } //移除蜂蜜,-MAX public synchronized void remove(){ while(count< MAX ){ try{ this.wait(); } catch(Exception e){ e.printStackTrace(); } } count=0; this.notifyAll(); } } //蜜蜂,生产者线程类 class Bee extends Thread{ private Pot pot; private String name; public Bee(String name, Pot pot){ this.name = name; this.pot = pot; } public void run(){ while(true){ int n = pot.add(); System.out.println(name+"生产了:"+n); } } } //熊,消费者线程类 class Bear extends Thread{ private Pot pot; private String name; public Bear(String name, Pot pot){ this.name = name; this.pot = pot; } public void run(){ while(true){ pot.remove(); System.out.println(name+"吃掉了蜂蜜:20!"); } } }
创建线程的方式
-
继承Thread类
-
实现Runnable接口
class Man extends Person implements Runnable{ public void run(){ ... } } new Car().start(); new Thread(new Man()).start();
java.lang.Runnable
-
接口
-
public void run();
-
供现有类实现线程功能
-
使用Runnable对象创建线程
-
静态同步方式是使用class作为锁
-
非静态同步方式是使用当前对象作为锁
new Thread(Runnable r).start(); class Car implements Runnable{ ... //静态同步方法 static synchronized void xxx(){ } } new Thread(Runnable r).start()
IDE
集成开发环境, integrate development environment
eclipse 快捷键:
- alt + / //代码辅助
- alt + 上箭头 //向上移动一行
- alt + 下箭头 //向上移动一行
- alt + shift + 上箭头 //向上复制一行
- alt + shift + 下箭头 //向下复制一行
- ctrl + D //删除一行
- ctrl + shift + / //多行注释
String
-
常量
String str = "xxx"; str = "ddd"; for(i<10000){ name = name + "" + i; }//堆溢出 byte b = (int)1234; //int a = (int)"123"; //String name = (String)123; String name = 123 + ""; Object o = new Dog(); Dog d = (Dog)o;
-
创建String 的区别
//一个对象 String str1 = "abc";//在字符串池中开辟了空间 //两个对象 String str2 = new String("abc");//在堆区分配了内存空间
-
split(String s) // 按照指定的字符切割字符串,形成String数组
"hello,,,world,".split(",");//最后的,不会生效
-
== //判断是否是同一对象。判断对象的内存地址
-
equals //是判断两个对象内容是否相同。
-
substring(int start) //取子串,包含start
-
substring(int start,int end) //取子串,前包后不包
-
重写subString(String src,int beginIndex,int length) //按索引及长度取子串,要有健壮性
public static String subString(String src, int beginIndex, int length) throws Exception { if(src==null) { throw new Exception("源串为空"); } if(!(beginIndex>=0 && beginIndex<src.length())) { throw new Exception("起始索引无效"); } if(!(length>0 && (beginIndex+length)<=src.length())) { throw new Exception("长度无效"); } return src.substring(beginIndex,beginIndex+length); }
包装类
-
byte Byte
-
short Short
-
int Integer
-
long Long
-
float Float
-
double Double
-
char Character
-
boolean Boolean
自动装箱:Integer i = 12; // Integer i = new Integer(12);
自动拆箱:Integer i =12; i++
包装类与基本数据类型区别
-
包装类是对象,默认值是null;
-
数字型基本数据类型默认是0;
-
基本数据类型可以直接参与运算;
编码初始
电报,电脑的传输,存储都是01010101
0000110 晚
1010100 上
0010100 喝
0010111 点
0000001 儿
000010 1010100 0010100 0010111 0000001
最早的'密码本'
-
ascii
7位二进制,涵盖了英文字母大小写,特殊字符,数字。
01000001 A
01000010 B
01000011 C
ascii,一个字节最多8位, 只能表示256种可能,太少 -
存储单位换算
1bit 8bit = 1byte
1byte 1024byte = 1KB
1KB 1024kb = 1MB
1MB 1024MB = 1GB
1GB 1024GB = 1TB -
万国码 unicode
-
起初:
1个字节可以表示所有的英文,特殊字符,数字等等
2个字节,16位表示一个中文,不够,unicode一个中文用4个字节,32位
你 00000000 00000000 00000000 00001000 -
Unicode 升级 utf-8 utf-16 utf-32
utf-8 一个字符最少用8位去表示:
1). 英文用8位 一个字节
2). 欧洲文字用16位去表示 两个字节
3). 中文用24位去表示 三个字节
utf-16 一个字符最少用16位去表示
-
-
gbk
中国人自己发明的,一个中文用两个字节,16位表示。String str = "a中b国c"; byte[] bytes = str.getBytes("iso8859-1"); System.out.println(bytes.length); //5, 欧洲码,没有中文字典 System.out.println(new String(bytes,"iso8859-1")); //a?b?c bytes = str.getBytes("gbk"); System.out.println(bytes.length); //7,一个字节表示英文字母,两个字节表示一个中文 System.out.println(new String(bytes,"gbk")); //a中b国c bytes = str.getBytes("utf-8"); System.out.println(bytes.length);//9, 英文一个字节,中文三个字节 System.out.println(new String(bytes,"utf-8")); bytes = str.getBytes("unicode");// -2 -1 0 97 78 45 0 98 86 -3 0 99 System.out.println(bytes.length);//12,中文四个字节,英文一个字节?为何是12? System.out.println(new String(bytes,"unicode")); String str2 = "a"; byte[] bytes2 = str2.getBytes("unicode");//-2 -1 0 97 String str3 = "中"; byte[] bytes3= str3.getBytes("unicode");//-2 -1 78 45 String str4 = "b"; byte[] bytes4 = str4.getBytes("unicode");//-2 -1 0 98 String str5 = "国"; byte[] bytes5 = str5.getBytes("unicode");//-2 -1 86 -3 String str6 = "c"; byte[] bytes6 = str6.getBytes("unicode");//-2 -1 0 99
作业
-
substring(String str, int beginIndex, int length);
返回一定长度的子串 -
找到自己名字对应的Unicode码