您的位置:首页 > 编程语言 > Java开发

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

2014-01-24 11:08 746 查看
--记录蛋疼的那些日子--

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

遇到下载只能到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.set
4000
Value(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();
}
}
}

}

}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 多线程 object java