多线程--线程同步、死锁、守护线程、多线程下载

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
			}
			
		}
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您好!如果我理解正确的话,您的问题是关于JMU Java 07多线程同步访问的。以下是我的回答: 多线程编程是指在一个程序中同时执行多个线程的编程技术。多线程编程在提高程序性能、增强程序交互性等方面有很大的优势,但也会引入一些问题,比如线程安全问题。 当多个线程同时访问共享资源时,可能会出现线程不安全的问题,比如数据竞争、死锁等。为了避免这些问题,我们需要使用同步机制来确保线程安全。 Java中提供了多种同步机制,比如synchronized关键字、ReentrantLock类、Semaphore类等。这些同步机制都可以用来保证多线程访问共享资源的安全性。 其中,synchronized是最常用的同步机制之一。在Java中,synchronized关键字可以用来修饰方法或代码块,以实现同步访问共享资源。synchronized可以保证在同一时间只有一个线程可以访问共享资源,从而避免了数据竞争等线程安全问题。 除了synchronized之外,Java还提供了一些其他的同步机制,比如ReentrantLock类和Semaphore类。ReentrantLock类提供了比synchronized更灵活的锁机制,可以实现可重入锁、公平锁等功能。Semaphore类可以控制同时访问共享资源的线程数量,从而避免资源被过度占用的问题。 总的来说,多线程编程是一项复杂而重要的技术,需要仔细研究和实践。在实际开发中,我们需要根据具体的需求选择合适的同步机制来确保多线程访问共享资源的安全性。 ### 回答2: 多线程编程是在当前计算机领域中最为常见的技术之一,它可以利用计算机中的多核处理器来使程序运行更加高效。但是,多线程编程中可能会出现的最大问题就是线程安全,因为线程之间可能会访问相同的资源,从而导致竞态条件。 在Java中,可以通过使用synchronized关键字来实现同步访问,从而避免线程安全问题。synchronized关键字可以用于两种不同的情形:同步方法和同步块。在同步方法中,方法是同步的,即每个线程在执行该方法时都需要获取该对象的锁,如果该锁已经被其他线程获取,则需要等待直到此锁被释放。在同步块中,需要手动指定锁,即每个线程在执行同步块时需要获取该指定锁,其他线程如果需要访问该代码块中的共享资源也需要获取该指定锁,这样就保证了该代码块中的所有共享资源的同步访问。 除了synchronized关键字外,Java还提供了其他一些同步机制来实现线程安全,如ReentrantLock类和CountDownLatch类等。ReentrantLock类可以实现更为灵活的同步访问控制,但需要手动释放锁;而CountDownLatch类则用于同步一个或多个线程,使这些线程在某个条件满足之前一直处于等待状态。 在进行多线程编程时,应该尽量避免对同步访问造成瓶颈,应该通过减小同步代码块的范围等方式来提高程序的效率。此外,多线程编程时还应该进行线程安全性的测试,以确保程序能够正确地运行。 ### 回答3: 在Java中,多线程是一种非常常见的编程方式。由于多线程的特点,对共享资源的访问会出现竞争的情况,这种竞争可能会导致数据不一致或程序异常等问题。因此,在多线程编程中,我们需要采取一些措施来保证共享资源的访问能够正确、有序地进行,这就是同步机制。 同步机制包括两种方式:锁和信号量。锁是最基本的同步机制。锁有两种类型:互斥锁(Mutex)和读写锁(ReadWriteLock)。互斥锁用于保护共享资源,保证同一时间只有一个线程可以访问它,其他线程需要等待锁释放后才能继续访问。读写锁用于读写分离场景,提高了多线程访问共享资源的并发性。读写锁支持多个线程同时读取共享资源,但只允许一个线程写入共享资源。 信号量是一种更加高级的同步机制。信号量可以用来控制并发线程数和限制访问共享资源的最大数量。在Java中,Semaphore类提供了信号量的实现。Semaphore可以控制的线程数量可以是任意的,线程可以一起执行,也可以分批执行。 除了锁和信号量,Java还提供了一些其他同步机制,比如阻塞队列、Condition等。阻塞队列是一种特殊的队列,它支持线程在插入或者删除元素时阻塞等待。Condition是一种锁的增强,它可以让线程在某个特定条件下等待或者唤醒。 在多线程编程中,使用同步机制需要注意以下几点。首先,同步机制要尽可能的保证资源访问的公平性,避免因为某些线程执行时间过长导致其他线程等待时间过长。其次,同步机制要尽可能的避免死锁的发生,尤其要注意线程之间的依赖关系。最后,同步机制的实现要尽可能地简单,避免过于复杂的代码实现带来的维护成本。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值