1 线程同步
当两个或多个线程需要访问同一资源时,需要确保该资源某一时刻只能被一个线程使用
1.1同步代码块
同步代码块:synchronized放在对象前面限制一段代码的执行
synchronized(对象)//这个对象可以为任意对象
{
需要被同步的代码
}
同步条件
必须要有两个或者两个以上的线程
必须是多个线程使用同一个锁
缺点
多个线程需要判断锁,较为消耗资源
案例
class TicketRes implements Runnable {
private int ticket = 10;// 票
Object object=new Object();
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized(object){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName()
+ "--->卖"
+ ticket--);
} else {
break;
}
}
}
}
}
1.2同步方法
同步非静态方法:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象,如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后
同步static方法: synchronized放在static方法声明中,表示锁定该类的class对象(Xxx.class,是Class类型的,是描述一个类的信息的对象)
如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后,其他非同步方法的执行不受影响.
public synchronized void method1(){
…
}
public synchronized static void method2(){
…
}
public synchronized void method3(){
…
}
1.3锁的选择
多个线程共享资源,为了保证数据安全,需要同步
一般情况下选择资源作为锁(必须为引用类型)即可,也可以选择其他唯一的对象
1.4同步代码块的应用
懒汉式单例模式
public class SingletonClass{
private static SingletonClass instance=null;
public static SingletonClass getInstance(){
if(instance==null){//提高性能
synchronized(SingletonClass.class){
if(instance==null){
instance=new SingletonClass();
}
}
}
return instance;
}
private SingletonClass(){}
}
2 死锁
所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
2.1死锁案例
public void run() {
if (flag) {
synchronized (MyLock.locka) {
System.out.println("if locka");
synchronized (MyLock.lockb) {
System.out.println("if lockb");
}
}
} else {
synchronized (MyLock.lockb) {
System.out.println("else lockb");
synchronized (MyLock.locka) {
System.out.println("else locka");
}
}
}
}
class MyLock {
static Object locka = new Object();
static Object lockb = new Object();
}
3 守护线程
在Java中有两类线程:
User Thread(用户线程或前台线程)
Daemon Thread(守护线程或后台线程)
其实User Thread线程和Daemon Thread守护线程本质上来说去没啥区别的,唯一的区别之处就在虚拟机的离开:如果User Thread全部撤离,那么Daemon Thread也就没啥线程好服务的了,所以虚拟机也就退出了。
案例
public class DreamThreadDemo {
public static void main(String[] args) {
//创建线程对象
DreamThread dt = new DreamThread();
dt.setDaemon(true);
dt.start();
for (int i = 0; i < 50; i++) {
System.out.println("主线程=============="+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class DreamThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; i++) {
System.out.println("子线程=============="+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4 利用RandomAccessFile实现文件的多线程下载,即多线程下载一个文件时, 将文件分成几块,每块用不同的线程进行下载((模拟复制实现)
public class DownLoadFile {
public static void main(String[] args) {
File file = new File("d:\\11.jpg");
long fileLen = 0;
if (file.exists()) {
fileLen = file.length();
}
int sublen = (int) (fileLen%4==0?fileLen/4:fileLen/4+1);
DownLoadThread d1 = new DownLoadThread(0, sublen);
DownLoadThread d2 = new DownLoadThread(sublen, sublen);
DownLoadThread d3 = new DownLoadThread(sublen*2, sublen);
DownLoadThread d4 = new DownLoadThread(sublen*3, (int)fileLen-sublen*3);
d1.start();
d2.start();
d3.start();
d4.start();
}
}
class DownLoadThread extends Thread{
private int skipCount;//要跳过的字节数
private int len;//下载的长度
public DownLoadThread(int skipCount, int len) {
super();
this.skipCount = skipCount;
this.len = len;
}
@Override
public void run() {
// TODO Auto-generated method stub
RandomAccessFile read =null;
RandomAccessFile write = null;
try {
System.out.println(Thread.currentThread().getName()+"开始下载");
read = new RandomAccessFile("d:\\11.jpg","rw");
write = new RandomAccessFile("d:\\22.jpg", "rw");
read.seek(skipCount);
write.seek(skipCount);
byte[] buff = new byte[len];
read.read(buff);
write.write(buff);
System.out.println(Thread.currentThread().getName()+"下载完成");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if (read!=null) {
read.close();
}
if (write!=null) {
write.close();
}
} catch (Exception e2) {
// TODO: handle exception
}
}
}
}