谈谈java线程锁synchronized关键字和volatile关键字

--记录蛋疼的那些日子--

最近和往常一样在群里聊天,一个哥们自己写了一个多线程下载程序,不知道他写来下片还是干吗,

遇到下载只能到99%的问题,但是呢下载下来的东西又能用,这让他头疼不已,

最后加了个synchronized(object){}搞定一切。

但是问题还在,刚好我闲来无事就查查资料学习学习。

-----------------------------------------群号183436336

先上代码



import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;

public class UpdateReceiver {
	private AtomicInteger length = new AtomicInteger(0);
	private RandomAccessFile accessFile;
	private int test = 0;
	private static Object object=new Object();
	private Integer nInteger = new Integer(0);
	class ITest{
		public Integer length = 0;
		public void setValue(int arg0){
			length = length + arg0;
		}
	}
	private volatile ITest itest = new ITest(); 
	
	private synchronized void setValue(int arg0,int threadId){
		//test = arg;
		test = test + arg0;
		/**
		 * 测试锁方法
		 */
		/*if(threadId==0){
			try {
				Thread.sleep(1000*10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}*/
	}

	/**
	 * 
	 * @param path 资源下载路径
	 * @param threadNum 线程数
	 * @param filepath 保存文件路径
	 */
	public void download(String path, int threadNum,String filepath) {
		try {
			URL url = new URL(path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setConnectTimeout(3000);
			conn.setRequestMethod("GET");
			if (conn.getResponseCode() == 200) {
				int fileLength = conn.getContentLength(); // 获取网络资源文件大小,有些服务器不支持暂时不考虑
				File file = new File(filepath);
				System.out.print(fileLength+"\n");
				accessFile = new RandomAccessFile(file, "rwd");
				accessFile.setLength(fileLength); // 设置保存文件的大小为获取到的大小
				int block = fileLength % threadNum == 0 ? fileLength/ threadNum : (fileLength / threadNum) + 1; // 计算文件应该分为几块
				System.out.println("block:"+block);
				for (int threadId = 0; threadId < threadNum; threadId++) {
					//新建线程开始下载
					new DownloadThread(threadId, block, path, file).start();
				}
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public class DownloadThread extends Thread {
		private int threadId;
		private int block;
		private String path;
		private File file;

		public DownloadThread(int threadId, int block, String path, File file) {
			this.threadId = threadId;
			this.block = block;
			this.path = path;
			this.file = file;
		}

		public void run() {
			super.run();
			int start = threadId * block; // 文件单块开始写入的位置
			int end = (threadId + 1) * block - 1; // 文件单块结束位置
			InputStream in = null;
			RandomAccessFile accessFile = null;
			try {
				accessFile = new RandomAccessFile(file, "rwd");
				accessFile.seek(start);//指定开始写入位置
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(3000);
				conn.setRequestMethod("GET");
				conn.setRequestProperty("Range", "bytes=" + start + "-" + end);// 设置从网络读取文件块位置
				System.out.println("bytes=" + start + "-" + end);
				if (conn.getResponseCode() == 206) {
					in = conn.getInputStream();
					byte[] buffer = new byte[1024*10];
					int len = 0;
					while ((len = in.read(buffer)) != -1) {
						/**
						 * 方法一:通过锁方法实现同步
						 * 当任意线程进入setValue()方法的时候,其它线程不得访问,需等待当前线程结束该方法
						 */
						{
							accessFile.write(buffer,0, len);
							setValue(len,threadId);
							System.out.println(test*100/accessFile.length()+"%");
						}
						/**
						 * 方法二:AtomicInteger原子操作,额。。。。。也没有详细研究
						 */
						/*{
							accessFile.write(buffer,0, len);
							length.addAndGet(len);
							System.out.println(length.get()*100/accessFile.length()+"%");
						}*/
						/**
						 * 方法三:加变量锁
						 * 当任意线程访问此块代码,其它线程需等待结束
						 */
						/*synchronized(object){
							accessFile.write(buffer,0, len);
							test = test + len;
							System.out.println(test*100/accessFile.length()+"%");
						} */
						/**
						 * 错误方法,volatile修饰的变量只能内存地址是一样的,不能lock方法
						 */
						 /*{
							accessFile.write(buffer,0, len);
							itest.setValue(len);
							System.out.println(itest.length*100/accessFile.length()+"%");
						}*/
						/**
						 * 方法四:同样变量锁 
						 */
						/*synchronized(itest){
							accessFile.write(buffer,0, len);
							itest.setValue(len);
							System.out.println(itest.length*100/accessFile.length()+"%");
						}*/
						/**
						 * 错误
						 */
						/*synchronized(nInteger){
							accessFile.write(buffer,0, len);
							nInteger = nInteger + len;//每次又创建一个新对象
							System.out.println(nInteger*100/accessFile.length()+"%");
						}*/
					}
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					System.out.println("length:"+threadId+":"+length);
					System.out.println("test:"+threadId+":"+test);
					if (accessFile != null && in != null) {
						accessFile.close();
						in.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值