我把几个网站的登录都写在一个程序上了!用多线程没多大用!分开会不会好点

多线程断点续传实践 - annegu - ITeye技术网站
* author:annegu&
annegu做了一个简单的Http多线程的下载程序,来讨论一下多线程并发下载以及断点续传的问题。
这个程序的功能,就是可以分多个线程从目标地址上下载数据,每个线程负责下载一部分,并可以支持断点续传和超时重连。
下载的方法是download(),它接收两个参数,分别是要下载的页面的url和编码方式。在这个负责下载的方法中,主要分了三个步骤。第一步是用来设置断点续传时候的一些信息的,第二步就是主要的分多线程来下载了,最后是数据的合并。
1、多线程下载:
public String download(String urlStr, String charset) {
this.charset =
long contentLength = 0;
CountDownLatch latch = new CountDownLatch(threadNum);
long[] startPos = new long[threadNum];
long endPos = 0;
// 从url中获得下载的文件格式与名字
this.fileName = urlStr.substring(urlStr.lastIndexOf("/") + 1, urlStr.lastIndexOf("?")&0 ? urlStr.lastIndexOf("?") : urlStr.length());
if("".equalsIgnoreCase(this.fileName)){
this.fileName = UUID.randomUUID().toString();
this.url = new URL(urlStr);
URLConnection con = url.openConnection();
setHeader(con);
// 得到content的长度
contentLength = con.getContentLength();
// 把context分为threadNum段的话,每段的长度。
this.threadLength = contentLength / threadN
// 第一步,分析已下载的临时文件,设置断点,如果是新的下载任务,则建立目标文件。在第4点中说明。
startPos = setThreadBreakpoint(fileDir, fileName, contentLength, startPos);
//第二步,分多个线程下载文件
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i & threadN i++) {
// 创建子线程来负责下载数据,每段数据的起始位置为(threadLength * i + 已下载长度)
startPos[i] += threadLength *
/*设置子线程的终止位置,非最后一个线程即为(threadLength * (i + 1) - 1)
最后一个线程的终止位置即为下载内容的长度*/
if (i == threadNum - 1) {
endPos = contentL
endPos = threadLength * (i + 1) - 1;
// 开启子线程,并执行。
ChildThread thread = new ChildThread(this, latch, i, startPos[i], endPos);
childThreads[i] =
exec.execute(thread);
// 等待CountdownLatch信号为0,表示所有子线程都结束。
latch.await();
exec.shutdown();
// 第三步,把分段下载下来的临时文件中的内容写入目标文件中。在第3点中说明。
tempFileToTargetFile(childThreads);
} catch (InterruptedException e) {
e.printStackTrace();
首先来看最主要的步骤:多线程下载。
首先从url中提取目标文件的名称,并在对应的目录创建文件。然后取得要下载的文件大小,根据分成的下载线程数量平均分配每个线程需要下载的数据量,就是threadLength。然后就可以分多个线程来进行下载任务了。
在这个例子中,并没有直接显示的创建Thread对象,而是用Executor来管理Thread对象,并且用CachedThreadPool来创建的线程池,当然也可以用FixedThreadPool。CachedThreadPool在程序执行的过程中会创建与所需数量相同的线程,当程序回收旧线程的时候就停止创建新线程。FixedThreadPool可以预先新建参数给定个数的线程,这样就不用在创建任务的时候再来创建线程了,可以直接从线程池中取出已准备好的线程。下载线程的数量是通过一个全局变量threadNum来控制的,默认为5。
好了,这5个子线程已经通过Executor来创建了,下面它们就会各自为政,互不干涉的执行了。线程有两种实现方式:实现Runnable接口;继承Thread类。
ChildThread就是子线程,它作为DownloadTask的内部类,继承了Thread,它的构造方法需要5个参数,依次是一个对DownloadTask的引用,一个CountDownLatch,id(标识线程的id号),startPosition(下载内容的开始位置),endPosition(下载内容的结束位置)。
这个CountDownLatch是做什么用的呢?
现在我们整理一下思路,要实现分多个线程来下载数据的话,我们肯定还要把这多个线程下载下来的数据进行合。主线程必须等待所有的子线程都执行结束之后,才能把所有子线程的下载数据按照各自的id顺序进行合并。CountDownLatch就是来做这个工作的。
CountDownLatch用来同步主线程,强制主线程等待所有的子线程执行的下载操作完成。在主线程中,CountDownLatch对象被设置了一个初始计数器,就是子线程的个数5个,代码①处。在新建了5个子线程并开始执行之后,主线程用CountDownLatch的await()方法来阻塞主线程,直到这个计数器的值到达0,才会进行下面的操作,代码②处。
对每个子线程来说,在执行完下载指定区间与长度的数据之后,必须通过调用CountDownLatch的countDown()方法来把这个计数器减1。
2、在全面开启下载任务之后,主线程就开始阻塞,等待子线程执行完毕,所以下面我们来看一下具体的下载线程ChildThread。
public class ChildThread extends Thread {
public static final int STATUS_HASNOT_FINISHED = 0;
public static final int STATUS_HAS_FINISHED = 1;
public static final int STATUS_HTTPSTATUS_ERROR = 2;
private DownloadT
private long startP
private long endP
private final CountDownL
// private RandomAccessFile tempFile =
private File tempFile =
//线程状态码
private int status = ChildThread.STATUS_HASNOT_FINISHED;
public ChildThread(DownloadTask task, CountDownLatch latch, int id, long startPos, long endPos) {
this.task =
this.startPosition = startP
this.endPosition = endP
this.latch =
tempFile = new File(this.task.fileDir + this.task.fileName + "_" + id);
if(!tempFile.exists()){
tempFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
public void run() {
System.out.println("Thread " + id + " run ...");
HttpURLConnection con =
InputStream inputStream =
BufferedOutputStream outputStream =
long count = 0;
long threadDownloadLength = endPosition - startP
outputStream = new BufferedOutputStream(new FileOutputStream(tempFile.getPath(), true));
} catch (FileNotFoundException e2) {
e2.printStackTrace();
for(int k = 0; k & 10; k++){
System.out.println("Now thread " + id + "is reconnect, start position is " + startPosition);
//打开URLConnection
con = (HttpURLConnection) task.url.openConnection();
setHeader(con);
con.setAllowUserInteraction(true);
//设置连接超时时间为10000ms
con.setConnectTimeout(10000);
//设置读取数据超时时间为10000ms
con.setReadTimeout(10000);
if(startPosition & endPosition){
//设置下载数据的起止区间
con.setRequestProperty("Range", "bytes=" + startPosition + "-"
+ endPosition);
System.out.println("Thread " + id + " startPosition is " + startPosition);
System.out.println("Thread " + id + " endPosition is " + endPosition);
//判断http status是否为HTTP/1.1 206 Partial Content或者200 OK
//如果不是以上两种状态,把status改为STATUS_HTTPSTATUS_ERROR
if (con.getResponseCode() != HttpURLConnection.HTTP_OK
&& con.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {
System.out.println("Thread " + id + ": code = "
+ con.getResponseCode() + ", status = "
+ con.getResponseMessage());
status = ChildThread.STATUS_HTTPSTATUS_ERROR;
this.task.statusError =
outputStream.close();
con.disconnect();
System.out.println("Thread " + id + " finished.");
latch.countDown();
inputStream = con.getInputStream();
int len = 0;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
outputStream.write(b, 0, len);
startPosition +=
//每读满4096个byte(一个内存页),往磁盘上flush一下
if(count % 4096 == 0){
outputStream.flush();
System.out.println("count is " + count);
if (count &= threadDownloadLength) {
status = ChildThread.STATUS_HAS_FINISHED;
outputStream.flush();
outputStream.close();
inputStream.close();
con.disconnect();
status = ChildThread.STATUS_HAS_FINISHED;
System.out.println("Thread " + id + " finished.");
latch.countDown();
} catch (IOException e) {
outputStream.flush();
TimeUnit.SECONDS.sleep(getSleepSeconds());
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
在ChildThread的构造方法中,除了设置一些从主线程中带来的id, 起始位置之外,就是新建了一个临时文件用来存放当前线程的下载数据。临时文件的命名规则是这样的:下载的目标文件名+”_”+线程编号。
现在让我们来看看从网络中读数据是怎么读的。我们通过URLConnection来获得一个http的连接。有些网站为了安全起见,会对请求的http连接进行过滤,因此为了伪装这个http的连接请求,我们给httpHeader穿一件伪装服。下面的setHeader方法展示了一些非常常用的典型的httpHeader的伪装方法。比较重要的有:Uer-Agent模拟从Ubuntu的firefox浏览器发出的请求;Referer模拟浏览器请求的前一个触发页面,例如从skycn站点来下载软件的话,Referer设置成skycn的首页域名就可以了;Range就是这个连接获取的流文件的起始区间。
private void setHeader(URLConnection con) {
con.setRequestProperty("User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/ Ubuntu/8.04 (hardy) Firefox/3.0.3");
con.setRequestProperty("Accept-Language", "en-us,q=0.7,zh-q=0.3");
con.setRequestProperty("Accept-Encoding", "aa");
con.setRequestProperty("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
con.setRequestProperty("Keep-Alive", "300");
con.setRequestProperty("Connection", "keep-alive");
con.setRequestProperty("If-Modified-Since", "Fri, 02 Jan :05 GMT");
con.setRequestProperty("If-None-Match", "\"0-df64d224\"");
con.setRequestProperty("Cache-Control", "max-age=0");
con.setRequestProperty("Referer", "");
另外,为了避免线程因为网络原因而阻塞,设置了ConnectTimeout和ReadTimeout,代码④处。setConnectTimeout设置的连接的超时时间,而setReadTimeout设置的是读取数据的超时时间,发生超时的话,就会抛出socketTimeout异常,两个方法的参数都是超时的毫秒数。
这里对超时的发生,采用的是等候一段时间重新连接的方法。整个获取网络连接并读取下载数据的过程都包含在一个循环之中(代码③处),如果发生了连接或者读取数据的超时,在抛出的异常里面就会sleep一定的时间(代码⑩处),然后continue,再次尝试获取连接并读取数据,这个时间可以通过setSleepSeconds()方法来设置。我们在迅雷等下载工具的使用中,经常可以看到状态栏会输出类似“连接超时,等待*秒后重试”的话,这个就是通过ConnectTimeout,ReadTimeout来实现的。
连接建立好之后,我们要检查一下返回响应的状态码。常见的Http Response Code有以下几种:
a) 200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
b) 206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成。
c) 404 Not Found 无法找到指定位置的资源。这也是一个常用的应答。
d) 414 Request URI Too Long URI太长。
e) 416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头。
f) 500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求。
g) 503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。
在这些状态里面,只有200与206才是我们需要的正确的状态。所以在代码⑤处,进行了状态码的判断,如果返回不符合要求的状态码,则结束线程,返回主线程并提示报错。
假设一切正常,下面我们就要考虑从网络中读数据了。正如我之前在分析mysql的数据库驱动中看的一样,网络中发送数据都是以数据包的形式来发送的,也就是说不管是客户端向服务器发出的请求数据,还是从服务器返回给客户端的响应数据,都会被拆分成若干个小型数据包在网络中传递,等数据包到达了目的地,网络接口会依据数据包的编号来组装它们,成为完整的比特数据。因此,我们可以想到在这里也是一样的,我们用inputStream的read方法来通过网卡从网络中读取数据,并不一定一次就能把所有的数据包都读完,所以我们要不断的循环来从inputStream中读取数据。Read方法有一个int型的返回值,表示每次从inputStream中读取的字节数,如果把这个inputStream中的数据读完了,那么就返回-1。
Read方法最多可以有三个参数,byte b[]是读取数据之后存放的目标数组,off标识了目标数组中存储的开始位置,len是想要读取的数据长度,这个长度必定不能大于b[]的长度。
public synchronized int read(byte b[], int off, int len);
我们的目标是要把目标地址的内容下载下来,现在分了5个线程来分段下载,那么这些分段下载的数据保存在哪里呢?如果把它们都保存在内存中是非常糟糕的做法,如果文件相当之大,例如是一个视频的话,难道把这么大的数据都放在内存中吗,这样的话,万一连接中断,那前面下载的东西就都没有了?我们当然要想办法及时的把下载的数据刷到磁盘上保存下来。当用bt下载视频的时候,通常都会有个临时文件,当视频完全下载结束之后,这个临时文件就会被删除,那么下次继续下载的时候,就会接着上次下载的点继续下载。所以我们的outputStream就是往这个临时文件来输出了。
OutputStream的write方法和上面InputStream的read方法有类似的参数,byte b[]是输出数据的来源,off标识了开始位置,len是数据长度。
public synchronized void write(byte b[], int off, int len) throws IOE
在往临时文件的outputStream中写数据的时候,我会加上一个计数器,每满4096个比特就往文件中flush一下(代码⑦处)。
对于输出流的flush,有些要注意的地方,在程序中有三个地方调用了outputStream.flush()。第一个是在循环的读取网络数据并往outputStream中写入的时候,每满4096个byte就flush一下(代码⑦处);第二个是循环之后(代码⑧处),这时候正常的读取写入操作已经完成,但是outputStream中还有没有刷入磁盘的数据,所以要flush一下才能关闭连接;第三个就是在异常中的flush(代码⑨处),因为如果发生了连接超时或者读取数据超时的话,就会直接跑到catch的exception中去,这个时候outputStream中的数据如果不flush的话,重新连接的时候这部分数据就会丢失了。另外,当抛出异常,重新连接的时候,下载的起始位置也要重新设置,所以在代码⑥处,即每次从inputStream中读取数据之后,startPosition就要重新设置,count标识了已经下载的字节数。
3、现在每个分段的下载线程都顺利结束了,也都创建了相应的临时文件,接下来在主线程中会对临时文件进行合并,并写入目标文件,最后删除临时文件。这部分很简单,就是一个对所有下载线程进行遍历的过程。这里outputStream也有两次flush,与上面类似,不再赘述。
private void tempFileToTargetFile(ChildThread[] childThreads) {
BufferedOutputStream outputStream = new BufferedOutputStream(
new FileOutputStream(fileDir + fileName));
// 遍历所有子线程创建的临时文件,按顺序把下载内容写入目标文件中
for (int i = 0; i & threadN i++) {
if (statusError) {
for (int k = 0; k & threadN k++) {
if (childThreads[k].tempFile.length() == 0)
childThreads[k].tempFile.delete();
System.out.println("本次下载任务不成功,请重新设置线程数。");
BufferedInputStream inputStream = new BufferedInputStream(
new FileInputStream(childThreads[i].tempFile));
System.out.println("Now is file " + childThreads[i].id);
int len = 0;
long count = 0;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
outputStream.write(b, 0, len);
if ((count % 4096) == 0) {
outputStream.flush();
// b = new byte[1024];
inputStream.close();
// 删除临时文件
if (childThreads[i].status == ChildThread.STATUS_HAS_FINISHED) {
childThreads[i].tempFile.delete();
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
4、最后,说说断点续传,前面为了实现断点续传,在每个下载线程中都创建了一个临时文件,现在我们就要利用这个临时文件来设置断点的位置。由于临时文件的命名方式都是固定的,所以我们就专门找对应下载的目标文件的临时文件,临时文件中已经下载的字节数就是我们需要的断点位置。startPos是一个数组,存放了每个线程的已下载的字节数。
//第一步,分析已下载的临时文件,设置断点,如果是新的下载任务,则建立目标文件。
private long[] setThreadBreakpoint(String fileDir2, String fileName2,
long contentLength, long[] startPos) {
File file = new File(fileDir + fileName);
long localFileSize = file.length();
if (file.exists()) {
System.out.println("file " + fileName + " has exists!");
// 下载的目标文件已存在,判断目标文件是否完整
if (localFileSize & contentLength) {
System.out.println("Now download continue ... ");
// 遍历目标文件的所有临时文件,设置断点的位置,即每个临时文件的长度
File tempFileDir = new File(fileDir);
File[] files = tempFileDir.listFiles();
for (int k = 0; k & files. k++) {
String tempFileName = files[k].getName();
// 临时文件的命名方式为:目标文件名+"_"+编号
if (tempFileName != null && files[k].length() & 0
&& tempFileName.startsWith(fileName + "_")) {
int fileLongNum = Integer.parseInt(tempFileName
.substring(tempFileName.lastIndexOf("_") + 1,
tempFileName.lastIndexOf("_") + 2));
// 为每个线程设置已下载的位置
startPos[fileLongNum] = files[k].length();
// 如果下载的目标文件不存在,则创建新文件
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return startP
public class DownloadStartup {
private static final String encoding = "utf-8";
public static void main(String[] args) {
DownloadTask downloadManager = new DownloadTask();
String urlStr = "/velocity/tools/1.4/velocity-tools-1.4.zip";
downloadManager.setSleepSeconds(5);
downloadManager.download(urlStr, encoding);
测试从apache下载一个velocity的压缩包,临时文件保留,看一下下载结果:
另:在测试从skycn下载软件的过程中,碰到了一个错误:
java.io.IOException: Server returned HTTP response code: 416 for URL: /
上网查了一下:416& Requested Range Not Satisfiable& 服务器不能满足客户在请求中指定的Range头,于是把threadNum改为1就可以了。
这个下载功能现在只是完成了很基础的一部分,最初的初衷就是为了演练一下CountdownLatch。CountdownLatch就是一个计数器,就像一个拦截的栅栏,用await()方法来把栅栏关上,线程就跑不下去了,只有等计数器减为0的时候,栅栏才会自动打开,被暂停的线程才会继续运行。CountdownLatch的应用场景可以有很多,分段下载就是一个很好的例子。
附件1是对应的java文件。
添加附件2,修改过的download,用RadomAccessFile,一个临时文件记录下载位置。
下载次数: 2886
下载次数: 3038
论坛回复 /
(47 / 55925)
con.setRequestProperty("Range", "bytes=" + startPosition + "-"& &&&&&&&&&&&&&&&&&&&&&&&&&&&& + endPosition);& 就不会被人忽视了。别人理解的你代码的重心就更好分配了。
代码应该把每个方法的代码行数都控制在10行之内。
不使用嵌套的控制块。
基本功有待提高啊。
apache mina, jpos的源代码也不是说所有的函数都很小。
但是楼主确实应该抽象、封装下比较好。
wandou 写道代码应该把每个方法的代码行数都控制在10行之内。
不使用嵌套的控制块。
基本功有待提高啊。
都控制10行,是不是太小了?如果代码多,那岂不是要分成很多个方法?
& 要根据业务来定的··一个方法最好别超过30行,反正原来一个方法里写的分到两个方法里去,绝对不会比在一个方法里快。
代码应该把每个方法的代码行数都控制在10行之内。
不使用嵌套的控制块。
基本功有待提高啊。
都控制10行,是不是太小了?如果代码多,那岂不是要分成很多个方法?
& 上一页 1
浏览: 77569 次
来自: 杭州
棒棒的。写得很好!
不过对下面所述的问题有一些不同的看法, 仅为个人观 ...
随便说说:发现几个问题,中国的程序员果然如传闻中的那样会随意指 ...
我想咨询你一个关于JMX的问题。
就是启动一个程序。
配置 ...有个问题想了很久。。。为什么我们的思维都是单线程的?。。。 | 死理性派小组 | 果壳网 科技有意思
888963人加入此小组
虽然说我们可以同时做很多事情:例如一边开车,一边打电话(危险~!);或者一边听歌,一边写作业。。。事实山,这个“一边。。。一边。。。”造句就是为了这种情况准备的。。。。但是无论如何我们却做不到将思维开多线程。试问有人能一边思考数学问题,一边构思英语作文吗?。。。我是说绝对的并发,不是先思考一会数学问题,再转过来思考一会作文,再转回去思考数学问题。。。而必须要是同步的,大脑中就如同开了多线程一般,同时处理两个思维过程。。。。很明显我们的大脑不支持这样做(虽然有些裂脑人,但是他们也最多只能支持双线程)。。。我们的大脑进化了这么久,为什么就没有进化出多线程呢??。。。。为什么我们的思维没有进化出同步机制呢??。。。
+ 加入我的果篮
有哦。。。比如那些,大多只在电影里出现的多重人格,亦或是精神分裂患者。。。。他们是多线程的吧。。。只是不兼容罢了。。。嗯等等。。。到底这些家伙算作多核处理器还是算作内存超大信息互不干扰?。。
电脑也没有真正意义上的多线程啊。。
的话:电脑也没有真正意义上的多线程啊。。有啊。。。多核处理器就是的。。。如果你还要更严格的多线程,可以考虑分布式计算。。。如果还要再科幻一点的,可以看看量子计算。。。
的话:有哦。。。比如那些,大多只在电影里出现的多重人格,亦或是精神分裂患者。。。。他们是多线程的吧。。。只是不兼容罢了。。。嗯等等。。。到底这些家伙算作多核处理器还是算作内存超大信息互不干扰?。。但是那样的话,思维就不再是自己的了。。。那就已经是分裂出来的思维了。。。可以认为书属于不同的进程的了,原本的思维和他们完全不相干。。。我说的是在同一个思维进程中,可以并发出来多个思维的线程。。。。
人和人和有区别的,有些人擅长专注于一件事,有些人擅长一心二用。去黑蝙蝠中队看看就知道了,飞行员是不能过分专注的,要考飞行员有这方面的测试,必须同时关注和思考多个事情。
的话:但是那样的话,思维就不再是自己的了。。。那就已经是分裂出来的思维了。。。可以认为书属于不同的进程的了,原本的思维和他们完全不相干。。。我说的是在同一个思维进程中,可以并发出来多个思维的线程。。。。会不会多个思维已经发生,只是我们没意识到?(以下属于胡思乱想:类似于云层对地放电初时蔓延的树状分支,虽然会有很多分支出现,但最终形成闪电的只有一条链。。)会不会我们的思维本就有超多可能线程出现,但存活下来,并有时间停滞在意识中的只有一条。。
电子工程专业
我觉得其实在一定程度上算多线程,虽然我们不能一边思考数学问题,一边构思英语作文。但是至少我们能一边打字一边想接下来要怎么回复。
语言爱好者
电脑的“多线程”也是分时复用的,不是“同时”的多线程。要“同时”多线程,必须得多核。而类比到人,人的一个脑就是一个“核”,要想多线程,就得有多个脑……ls说的一边打字一边想怎么回复,这两个能够并行的原因是二者利用的脑区不同。
可是我们能一边吃饭一边喝汤啊!?!
的话:电脑的“多线程”也是分时复用的,不是“同时”的多线程。要“同时”多线程,必须得多核。而类比到人,人的一个脑就是一个“核”,要想多线程,就得有多个脑……ls说的一边打字一边想怎么回复,这两个能够并行的原因是二者利用的脑区不同。连体婴儿?
我觉得就是多线程的,很多行为不是由自己的意识,而是由潜意识决定的
因为我们是单核系统。
不知道用电脑来比喻合不合适CPU和内存摆在那了,脑容量和IQ也摆在那了可以同时做些内存占用小的事情,如一边听歌同时寻找党的先进性教育正如可以开车时左顾右盼,时不时看后视镜,调节车载频道什么的如果是开着孤岛危机和地铁2033,必然有一个兼顾不来
软件工程师,小众软件爱好者
的话:我觉得就是多线程的,很多行为不是由自己的意识,而是由潜意识决定的那个就是因为利用的闹区不同.
的话:会不会多个思维已经发生,只是我们没意识到?(以下属于胡思乱想:类似于云层对地放电初时蔓延的树状分支,虽然会有很多分支出现,但最终形成闪电的只有一条链。。)会不会我们的思维本就有超多可能线程出现,但存活下来,并有时间停滞在意识中的只有一条。。你没明白我的意思。。。大脑确实可以同时做多件事情。。。但是思维或者自我意识在某一时刻只能停留在某件事上面。。。。
的话:电脑的“多线程”也是分时复用的,不是“同时”的多线程。要“同时”多线程,必须得多核。而类比到人,人的一个脑就是一个“核”,要想多线程,就得有多个脑……ls说的一边打字一边想怎么回复,这两个能够并行的原因是二者利用的脑区不同。大脑的结构应该更类似于原胞自动机,而不是CPU。。。所以按道理说,进化出并发机制应该不是问题,但为什么我们的意识或者思维每次仅仅只能专注于一件事情呢?——举个最简单的例子,同时收听一个中文电台和英文电台,你能同时接受两边过来的信息,并在一段时间后复述出它们的大概内容吗?。。。。
的话:会不会多个思维已经发生,只是我们没意识到?(以下属于胡思乱想:类似于云层对地放电初时蔓延的树状分支,虽然会有很多分支出现,但最终形成闪电的只有一条链。。)会不会我们的思维本就有超多可能线程出现,但存活下来,并有时间停滞在意识中的只有一条。。同意
当然可以,但大脑没有线程这个说法,正确的说,应该是说注意力。如果有合适的锻炼过程,大脑是可以同时注意多个事物,一般来说同时只注意一个事物其实是和我们的眼睛有关,眼睛其实只有一小块区域是高分辨率的,很多时候注意力都是靠眼睛的视觉点来体现,所以我们只是习惯一次注意一件事物。如果是和视觉无关的思维,同时注意完全是可以的,只是要有长时间的锻炼过程来习惯。
第一:佛法说一刹那的时间我们会有许多想法的,只是不知道怎么后来又集中到某一个主题上的。第二:关于同时思考两个以上的主题的问题,我觉得应该依据相对论解释的同时性概念。它说的是同时性是与惯性系相关的,而我们大脑作为思考的主体时,是什么在运动,什么是其惯性系呢?没有这些同时性概念就不好确定啊。
的话:如果是和视觉无关的思维,同时注意完全是可以的,只是要有长时间的锻炼过程来习惯。好吧,从现在开始你就开始训练同时收听两个电台。。。或者一边看电视,一边听广播。。。。
相对论在宏观宇宙方面对时间的解释相当成功,然而对思维领域的时间解释好象很少啊。其是否可以应用到思维领域,又或其是否在思维领域有效?当然在思维领域有其自己正确的时间理论当然更简单了。不知道在思维领域有没有这一理论?
为啥你在走路的时候,还能一边哼歌?
的话:好吧,从现在开始你就开始训练同时收听两个电台。。。或者一边看电视,一边听广播。。。。好吧,是互不干涩的感觉引发的思维。不过一般电视电台什么的用不着思维。谁没见过女性一边打毛衣一边看电视。
楼主的的提问使我想到一个问题,借宝地一问:我们在物理界的相对理论和量子理论,数学上的微积分,有没有应用到思维领域啊?如果我们的大脑可以认识到这些知识,那么这些知识为什么不能应用到大脑的研究呢?
的话:为啥你在走路的时候,还能一边哼歌?我之前就说了,走路不需要思维。。。这是大脑其他区域自动计算完成的。。。。我说的两件不能同时做的事情都是需要思维意识活动参与的——例如一边听听力,一边解数学题。。。。
人机手谈小组管理员
的话:楼主的的提问使我想到一个问题,借宝地一问:我们在物理界的相对理论和量子理论,数学上的微积分,有没有应用到思维领域啊?如果我们的大脑可以认识到这些知识,那么这些知识为什么不能应用到大脑的研究呢?脑科学有些这方面的假说与研究
的话:电脑的“多线程”也是分时复用的,不是“同时”的多线程。要“同时”多线程,必须得多核。而类比到人,人的一个脑就是一个“核”,要想多线程,就得有多个脑……ls说的一边打字一边想怎么回复,这两个能够并行的原因是二者利用的脑区不同。终于有计算机专业的来了。引用
的话:你没明白我的意思。。。大脑确实可以同时做多件事情。。。但是思维或者自我意识在某一时刻只能停留在某件事上面。。。。这个取决于你如何定义“事情”吧。举个例子:你想象两个点A,B同时在朝一个方向移动。你可以认为这是两件事“A在移动”和“B在移动”,也可以认为是一件事“有两个点在移动”。另外,可能精神分裂症患者是在同时想不同的事。当然也可能是时分的……
的话:电脑的“多线程”也是分时复用的,不是“同时”的多线程。要“同时”多线程,必须得多核。而类比到人,人的一个脑就是一个“核”,要想多线程,就得有多个脑……ls说的一边打字一边想怎么回复,这两个能够并行的原因是二者利用的脑区不同。人的一个脑就是一个“核”。。。我一个CPU里面还有四个”核”呢~~~~人脑如果是这样未免太低效了吧。。。。。。。。。。
人脑是多线程的,但心理的抽象关注点(或抽象主动意识)只有一个。比如声音和图像都会同步处理,看电影的时候既能听到声音又能看到图像。
的话:人脑是多线程的,但心理的抽象关注点(或抽象主动意识)只有一个。比如声音和图像都会同步处理,看电影的时候既能听到声音又能看到图像。我知道这点啊~~~~所以我才问为什么“思维是单线程的”啊。。。。所谓“思维”,不就是“心理的抽象关注点(或抽象主动意识)”么。。。。LS一群人给我答非所问,LZ我很郁闷+纠结啊~~~~~为什么“心理的抽象关注点(或抽象主动意识)只有一个”???
的话:我之前就说了,走路不需要思维。。。这是大脑其他区域自动计算完成的。。。。我说的两件不能同时做的事情都是需要思维意识活动参与的——例如一边听听力,一边解数学题。。。。有的人是可以边听音乐边看书的。
的话:我知道这点啊~~~~所以我才问为什么“思维是单线程的”啊。。。。所谓“思维”,不就是“心理的抽象关注点(或抽象主动意识)”么。。。。LS一群人给我答非所问,LZ我很郁闷+纠结啊~~~~~为什么“心理的抽象关注点(或抽象主动意识)只有一个”???不这样人行为就不能一致呗。如果有两个思维都能控制身体,身体听哪个?
的话:人的一个脑就是一个“核”。。。我一个CPU里面还有四个”核”呢~~~~人脑如果是这样未免太低效了吧。。。。。。。。。。同意Maigo的看法。。看到过胼胝体被切断的文章。左右边表现出分别独立的意识。这个时候应该像是Pentium双核,仅仅是物理地两个核封装在一起的。可以算作是两个“脑”吧。。正常人没被切断的时候,胼胝体作为内部bus工作。。两个半脑可以视为一个脑。。。另外平日里的一边。。。一边。。。我赶脚有点像超线程技术。。
的话:那个就是因为利用的闹区不同.我赶脚有点像超线程技术。。
的话:我之前就说了,走路不需要思维。。。这是大脑其他区域自动计算完成的。。。。我说的两件不能同时做的事情都是需要思维意识活动参与的——例如一边、听听力,一边解数学题。。。。我觉得楼主对于定义的需要思维意识活动参与这个概念有问题,为啥“自动计算”就不能算是思维活动呢?走路算自动,好吧,那开车算什么?
的话:我觉得楼主对于定义的需要思维意识活动参与这个概念有问题,为啥“自动计算”就不能算是思维活动呢?走路算自动,好吧,那开车算什么? 好吧。。。那些一边开车一边打手机的最后会这样?。。。。
的话:不这样人行为就不能一致呗。如果有两个思维都能控制身体,身体听哪个?双头蛇并不是很罕见。。。那么双头蛇的身体听哪个头的呢?。。。答案很明显,两个头都听。。。所以经常你会见到它在原地打转——那是因为两个头的意向出现了分歧。。。。
该内存不能为“read”。。
的话:电脑也没有真正意义上的多线程啊。。如果人脑可以多线程的话,电脑绝对会出现多线程的。毕竟电脑是为了人的操作而设计。
的话:如果人脑可以多线程的话,电脑绝对会出现多线程的。毕竟电脑是为了人的操作而设计。他们说的对,电脑有多线程,就是多核处理,人脑也有,不同脑区同时处理问题就是
记的有篇科幻小说,某个人在药物的作用下,大脑别的非常发达。于是他在自己脑中构建了一个虚拟脑,用来对付那些可能对大脑有害的思维,呃……
个人觉得啊,潜意识就像是后台进程,主观意识就像是前台应用程序。
有啊,一边看动作片一边单手操作。
的话:个人觉得啊,潜意识就像是后台进程,主观意识就像是前台应用程序。除非你是智能手机。。。前台只跑一个进程。。。。
的话:他们说的对,电脑有多线程,就是多核处理,人脑也有,不同脑区同时处理问题就是问题是处理的问题都不是思维的啊。。。。思维一个时间是能有一个,不能并发思维。。。。要是能并发思维那就牛逼了:一边思考数学作业,一边构思英语作文,还能同时不受影响的看电视节目。。。。这是多么的效率啊~~~~~~
你以为你是小草履虫啊
的话:你以为你是小草履虫啊难道草履虫这种低级生物支持并发?!!!。。。。。。。
的话:难道草履虫这种低级生物支持并发?!!!。。。。。。。我只知道小草履虫是双核的……
的话:我只知道小草履虫是双核的……那只能算是一个bug,不能算是优势。。。。。
的话:那只能算是一个bug,不能算是优势。。。。。当然有优势啊。把大小草履虫放在一起养,小草履虫就把大草履虫给竞争死了。
(C)2017果壳网&&&&京ICP证100430号&&&&京网文[-239号&&&&新出发京零字东150005号&&&&
违法和不良信息举报邮箱:&&&&举报电话:}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信