📄 day12.txt
字号:
CoreJava(day12) 2007-12-18 -- 李艳
同一个线程只能用start()启动一次。
多线程编码多半采用实现接口的方式
一个线程必须有自己的虚拟cpu
一个线程可以和其他线程共享代码和数据
synchronized可以加在方法层也可以加在代码块
当对一个方法或一个代码块加上后,意味着线程在同步代码中必须采用串行访问,不能再并行。
Synchronized用法
1.Synchronized修饰代码块(同步代码块),
public void push(char c){
synchronized(this)//只有持有当前对象锁标记的线程才能访问这个代码块,this就是对象锁,锁定代码块
{
...
}
}
对括号内的对象加锁,只有拿到锁标记的对象才能执行该代码块
2.Synchronized修饰方法
public synchronized void push(char c) {
...
}
在整个方法里,对当前对象的加锁,只有拿到锁标记的对象才能执行该方法。
对共享数据的读和写要一起同步,一般来说属性表示共享数据。
同步的问题:串行,大大的降低效率。
尽可能不要在方法层使用同步,使用synchronized。
所有的对象都有对象锁,一个钥匙。
池:池就是内存常驻
常量池、线程池、DB连接池、等待池、同步池、对象池
好处:快
坏处:占去了部分内存
同步最怕死锁
对象锁正在使用的对象不能直接操作。
interrupt()也会从运行状态到阻塞状态
stop()存在潜在的安全隐患,所以不再用。
1、对象-->锁--->对立
2、同步依赖对象锁(对象)、锁对象相同,同步语句串行
避免死锁:要保持顺序锁,不要回调,反向打开
因为线程的死锁,从而引发要多线程的通信
死锁:每个线程不释放自己拥有的资源,却申请别的线程拥有的资源,会造成死锁问题
没有获得加锁对象的锁标记的线程,不能访问只有获得该对象所标记才能访问的同步方法,但可以访问这个对象的非同步的方法。
例: t1 t2
synchronized(o1){ synchronized(o2){
synchronized(o2){ synchronized(o1){
} }
} }
t1和t2会形成死锁
Vector,Hashtable,StringBuffer 这些是同步的。
ArrayList,HashSet,StringBuild 这些是不同步的。
得到一个同步的ArrayList: List list=Collections.synchronizedList(new ArrayList());----外同步
List list=new Vector();-----外同步
wait();参数可选,可以是0个,1个,2个。 对象锁,放锁,自己等。
用 notify(); notifyAll(); 唤醒wait();
notify()随机唤醒一个,notifyAll()全部唤醒,随机选。
调用wait()方法表示让正在执行的线程停止执行进入对象的等待队列去等待,同时释放掉对象的锁
注意:只能对加锁的资源进行wait()和notify()。
1) wait():交出锁和CPU的占用;
2) notify():将从对象的等待池中移走一个任意的线程,并放到锁池中,那里的对象一直在等待,直到可以获得对象的锁标记。
3) notifyAll(): 将从等待池中移走所有等待那个对象的线程并放到锁池中,只有锁池中的线程能获取对象的锁标记,锁标记允许线程从上次因调用wait()而中断的地方开始继续运行
怎么用线程?
1、extends Thread,无共享时使用
2、implements Runnable,有共享时使用
同步有什么用:
线程是共享堆、独享栈的,所以有可能发生两个线程同时操作同一块内存。
同步可以使共同的操作变成单独操作。
同步原理:对象锁+同步
对象锁是对象所特有的锁,简单类型不是对象,没有锁。
同步的优缺点:
为了安全,同步不得不用。缺点就是效率非常低下。
多线程编码:
1、实现线程采用Runnable接口。
2、有共享数据的冲突用同步
3、避免死锁(采用顺序锁,不要回调)
4、若使用wait,notify进行交互时的原则
(1)用notifyAll代替notify
(2)wait是在同步语句的内部,用while循环
在什么情况下放锁(交钥匙):
1、同步代码执行完毕
2、异常未处理
3、wait()方法
I/O流
输入流 InputStream
输出流 OutputStream
输入、输出是针对程序而言的。
常用的输入字节流:
FileInputStream:文件字节流
ObjectInputStream:对象字节流
BufferedInputStream:缓冲输入流
常用的输出流:
FileOutStream:文件输出流
ObjectOutputTream:对象输出流
BufferedOutputStream:缓冲输出流
PrintStream:打印流
1)三个基本的read()方法
a. int read(): 从流里读出的一个字节或者-1; (实际读了多长) 从此输入流中读取一个数据字节。 返回下一个数据字节;如果已到达文件末尾,则返回 -1。
b. int read(byte[]):将数据读入到字节数组中,并返回所读的字节数; (期望读了多长)
从此输入流中将最多 b.length 个字节的数据读入一个字节数组中。
返回:读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
c. int read(byte[], int off, int len):两个int参数指定了所要填入的数组的子范围。 从此输入流中将最多 len 个字节的数据读入一个字节数组中
2) 其它方法
a. void close(): 关闭流,如使用过滤器流,关闭最外部的流,会关闭其余的流。 关闭此文件输入流并释放与此流有关的所有系统资源
b. int available(): 返回可从流中读取的字节数。
c. skip(long): 丢弃了流中指定数目的字符。
d. boolean markSupported()
e. void mark(int)
f. void rese()
1) 三个基本的write()方法
a. void write():
b. void write(byte[]):
c. void write(byte[], int , int)
2) 其它方法
a. void close(): 关闭流,如使用过滤器流,关闭最外部的流,会关闭其余的流。
b. void flush(): 允许你强制执行写操作。
注意:在流中close()方法由程序员控制。因为输入输出流已经超越了JVM的边界,所以有时可能无法回收资源。
原则:凡是跨出虚拟机边界的资源都要求程序员自己关闭,不要指望垃圾回收。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -