一,多线程

  多线程是提高程序效率,避免资源浪费的很好的解决方案,下面来慢慢的介绍多线程的一些基本知识,而这些是晋级高级不可或缺的一部分

  1,Thread类

  类实现多线程需要实现Runnable接口,我们跟踪一下源码,如下所示:

public
class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
........
}

Thread类实现了Runnable的接口,然后我们来看一下Runnable接口里面有什么东西,如下所示,哦,原来就一个run方法

public
interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p> 意思是说,实现runnable的接口后的对象可以用来创建一个线程,并且这个线程是通过run方法来运行的
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

那么回过头来看看,Thread类中的重写的这个run方法是什么?

    /**注意,这个注释的意思是说当用一个单独的Runnable对象来构造Thread线程的时候,Runnbalb对象的run方法将会被调用,否则,这个方法不起任何作用
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}

那么,这个target是什么鬼?继续追踪

    /* What will be run. */
private Runnable target;

好了,上面说的是背景知识,下面来真材实料吧。

初始化线程的方法有两个,

1,直接重写Thread类的run方法,注意,如果此时给Thread的构造函数传递一个Runnable对象,这个runnable对象的run方法不起任何作用,因为重写的run方法没有调用父类的run方法

2,直接给Thread传递一个runnable对象,调用对象的run方法

方法1:

        Thread tr = new Thread(){
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread test");
}
}
};
tr.start();

方法2:

        Thread tr2 = new Thread(new Runnable() {

            @Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("runnable test");
}
}
}){};
tr2.start();

针对方法1,我们这有一个小小的验证

当我们同时传递一个runnable对象和重写run方法时,结果会怎样呢?很明显,重写的run方法后,不会调用原来的那个target相关的操作了,也就是说传递进去的runnable没任何作用了,下面验证一下:

        new Thread(new Runnable() {

            @Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("in runnbale");
}
}
}){
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("in thread");
}
}
}.start();
}

运行结果是:

in thread
in thread
in thread
in thread
in thread
in thread
in thread

 二,定时器

这里主要介绍

Timer和TimerTask两个类

Timer类是声明一个定时器类,声明的时候可以给这个类提供一个TimerTask类的对象,注意,我们追踪一下这个TimerTask类,看到源码如下:

public abstract class TimerTask implements Runnable {
public abstract void run();
................
}

也就是说,这个类继承了runnable接口,意思就是说这个类最终是要生成一个Thread来进行TimerTask里面的run方法的。由此可见,定时器就是定时生成一个新的线程,然后这个新线程来执行run方法里的操作来的。

至于Timer里不同的构造参数,可以参考sdk里面的相关内容来学习。定时器就讲到这里了。

三,线程互斥

在实际生活中,我们会出现很多线程使用一个资源的问题,这些线程可能会抢夺资源,或者在某一时间段内,只能一个线程来使用资源,这个时候我们就需要用synchronized来进行线程间的互斥,下面来介绍一下线程互斥的问题

首先,我们建一个类,或者在一个类里将可能共同访问的资源给他一把锁,锁住这个资源,如下所示

    public class test {
public void displayit(String name) {
synchronized (this) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}

这个锁就是synchronized,锁住的是test这个对象,也就是说对这个对象的访问都需要看看这个对象是否已经被锁住

下面,我们开两个线程,来一直不停的访问这个对象,并输出访问内容,如下所示

    public void init() {
final test2 t = new test2();
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(10);
t.displayit("leeyangyang"); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(10);
t.displayit("weijunjun");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}

然后我们在main方法里调用这个方法

public class Sync {

    /**
* @param args
*/
public static void main(String[] args) {
new Sync().init();
}
..............................

最后我们得到的结果是:

leeyangyang
weijunjun
leeyangyang
weijunjun

然后再引伸一下,如果传递进去的是静态类,那么锁住的应该是什么参数呢?很明显,答案是静态类.class,具体的如下所示:

    public static class test2 {
public void displayit(String name) {
synchronized (test2.class) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}

好了,线程互斥就介绍到这里了。

四,线程同步通信

进程间的通信是通过wait()和notify()来实现的,当等待一个资源时,用wait()方法,使用后,注意将资源释放或者重新标注一下,如下面所示,要实现的是子线程跑10次,然后主线程跑10次,然后子线程再跑10次,主线程跑10次,这样,一共持续50遍。

思路:

1,先实现主线程和子线程都跑10次50遍,

2,根据互斥规则,跑得时候,两者互不打扰

3,给一个信号,当子线程正在执行的时候,主线程会在等待,子线程执行完之后,通知一下等待的线程,然后主线程得到这个通知后,开启线程。

看下面代码:

public class Synch2 {
public static void main(String[] args) {
new Synch2().init();
} public void init() {
final test2 t = new test2();
// 现开启一个子线程,然后根据子线程
new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
t.sub(i);
}
}
}).start(); for (int i = 1; i < 50; i++) {
synchronized (Synch2.class) {
t.maintest(i);
}
}
} public class test2 {
boolean subUsed = true; public synchronized void sub(int i) {
while (!subUsed) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 0; j < 10; j++) {
System.out.println("inn the subthread, num=" + j + " and loop "
+ i);
}
subUsed = false;
this.notify();// 通知所有的正在等待的线程
} public synchronized void maintest(int i) {
while (subUsed) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 0; j < 10; j++) {
System.out.println("inn the main thread, num=" + j
+ " and loop " + i);
}
subUsed = true;
this.notify();
}
}
}

这里有一个细节,就是在等待信号的时候,我们使用的是while,其实if也可以,但是我们使用的是while,原因是

可能其他原因导致了notify出现,但是while的条件仍不满足,这个时候,仍然会等待,但是如果是if的话,情况并不是这样

五,线程共享变量

线程内的变量在进行共享时,可以在外部新建一个map对,将变量放进去,然后,同一个线程内的对象可以共享变量

具体的代码如下

package cn.unis;

import java.util.HashMap;
import java.util.Map;
import java.util.Random; public class SyncShare {
final static Map<Thread , Object> maps = new HashMap<Thread, Object>();
public static void main(String[] args) {
new SyncShare().init();
} public void init(){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt(100);
maps.put(Thread.currentThread(), data);
new a().display();
new b().display();
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt(100);
maps.put(Thread.currentThread(), data);
new a().display();
new b().display();
}
}).start();
} public static class a{
public void display(){
System.out.println(Thread.currentThread().getName()+" get a data is " + maps.get(Thread.currentThread()));
}
} public static class b{
public void display(){
System.out.println(Thread.currentThread().getName()+" get b data is " + maps.get(Thread.currentThread()));
}
}
}

执行效果如下

Thread-0 get a data is 73
Thread-1 get a data is 89
Thread-0 get b data is 73
Thread-1 get b data is 89

六,多线程访问共享对象和数据的方式

分为两种情况,

1,每个线程执行的代码相同,比如说售票系统等,可以使用同一个runnable对象,这个runnable对象中有那个共享数据

2,每个线程执行的代码不同,比如说一个相加,一个相减,这个时候就需要不同的runnable对象,具体的可以分为下面几种数据共享的方式

a,将共享数据封装带另外一个对象中,然后将这个对象逐一传递给各个runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据斤西瓜的每个操作的互斥和通信。

b,将这些runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个runnable对象调用外部类的这些方法

c,上面两种方法的组合,将共享数据封装到另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量货方法中的局部变量,每个线程的runnale 对象作为外部类中的成员内部类和局部内部类

d,总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放到同一个类中,这样比较容易实现他们之间的同步互斥和通信

(原创)JAVA多线程一传统多线程的更多相关文章

  1. Java 中传统多线程

    目录 Java 中传统多线程 线程初识 线程的概念 实现线程 线程的生命周期 常用API 线程同步 多线程共享数据的问题 线程同步及实现机制 线程间通讯 线程间通讯模型 线程中通讯的实现 @(目录) ...

  2. 原创Java多线程详解(一)

    只看书不实践是不行的.来实践一下~~~~~~(引用请指明来源) 先看看百科对多线程的介绍 多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的 ...

  3. Java 并发和多线程(一) Java并发性和多线程介绍[转]

    作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...

  4. Java基础】并发 - 多线程

    Java基础]并发 - 多线程 分类: Java2014-05-03 23:56 275人阅读 评论(0) 收藏 举报 Java   目录(?)[+]   介绍 Java多线程 多线程任务执行 大多数 ...

  5. Java高并发与多线程(四)-----锁

    今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...

  6. Java学习手记2——多线程

    一.线程的概念 CPU执行程序,就好比一个人在干事情一样,同一个时间你只能做一件事情,但是这样的效率实在是太低了,在你用电脑的时候,听歌就不能浏览网页,看电影就不能下载视频,你想想是不是很蛋疼. 所以 ...

  7. java 并发性和多线程 -- 读感 (一 线程的基本概念部分)

    1.目录略览      线程的基本概念:介绍线程的优点,代价,并发编程的模型.如何创建运行java 线程.      线程间通讯的机制:竞态条件与临界区,线程安全和共享资源与不可变性.java内存模型 ...

  8. Java 并发性和多线程

    一.介绍 在过去单 CPU 时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个 ...

  9. Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

    1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...

随机推荐

  1. UDS(ISO14229-2006) 汉译(No.4 术语和缩写)

    A_PCI                    Application layer Protocol Control Information应用层协议控制消息. A_PDU              ...

  2. html基础大全(经典)

    HTML教程 一.HTML基础(人) 1.基础概念: 1.1.自动闭合标签和闭合标签(如出错html编写时不会报错) 自闭合:<mete  /> 闭合:<table>文字< ...

  3. jQuery属性/CSS使用例子

    jQuery属性/CSS 1..attr() 获取匹配的元素集合中的第一个元素的属性的值  或 设置每一个匹配元素的一个或多个属性. 例1:获取元素的属性的值 <p title="段落 ...

  4. iOS 苹果开发证书失效的解决方案(Failed to locate or generate matching signing assets)

    从2月14日开始,上传程序的同学可能会遇到提示上传失败的提示. 并且打开自己的钥匙串,发现所有的证书全部都显示此证书签发者无效. 出现以下情况: Failed to locate or generat ...

  5. 一起来学习android自定义控件3——边缘凹凸的View

    前言 最近做项目的时候遇到一个卡劵的效果,由于自己觉得用图片来做的话可以会出现适配效果不好,再加上自己自定义view方面的知识比较薄弱,所以想试试用自定义View来实现.先看设计图效果 实现分析 上面 ...

  6. 自定义 URL Scheme 完全指南(转载)

    iPhone / iOS SDK 最酷的特性之一就是应用将其自身”绑定”到一个自定义 URL scheme 上,该 scheme 用于从浏览器或其他应用中启动本应用. 注册自定义 URL Scheme ...

  7. h5曲线滑动确认

    h5项目需根据几条弯曲的线条让用户进行曲线式滑动,滑动时需实时响应某些样式,于是就有了下面这个实例.(可自定义多个子对象大小分别放在线条各处,以增加曲线滑动确认精度.) <!doctype ht ...

  8. WebForm(四)——Repeater控件(重要、好用)

    Repeater控件,可以用来一次显示一组数据项.比如,可以用它们显示一个数据表中的所有行.             Repeater控件完全由模板驱动,提供了最大的灵活性,可以任意设置它的输出格式. ...

  9. OAF messageChoice 关联问题

    最近有个需求,就是采购订单的供应商要按照一级和二级来选,一级关联二级,二级关联供应商.之前的一级和二级都是用LovInput做的,现在想要改为messageChoice.如下图: 改为: 下面给大家介 ...

  10. [解决]Mercurial HTTP Error 500: Access is denied on 00changelog.i

    总之,用户对仓库目录要有写权限 00changelog, access is denied, hg, http error 500, mercurial, permissions, push Merc ...