JAVA专题技术综述之线程篇

大庄生态养殖

大庄生态养殖

2016-02-19 11:57

想不想get新技能酷炫一下,今天图老师小编就跟大家分享个简单的JAVA专题技术综述之线程篇教程,一起来看看吧!超容易上手~
编写具有多线程能力的程序经常会用到的方法有:

run(),start(),wait(),notify(),notifyAll(),sleep(),yield(),join()

还有一个重要的关键字:synchronized

本文将对以上内容进行讲解。

一:run()和start()

示例1:

public class ThreadTest extends Thread
{
public void run()
{
for(int i=0;i 10;i++)
{
System.out.print(" " + i);
}
}
public static void main(String[] args)
{
new ThreadTest().start();
new ThreadTest().start();
}
}

这是个简单的多线程程序。run()和start()是大家都很熟悉的两个方法。把希望并行处理的代码都放在run()中;stat()用于自动调用run(),这是JAVA的内在机制规定的。并且run()的访问控制符必须是public,返回值必须是void(这种说法不准确,run()没有返回值),run()不带参数。

这些规定想必大家都早已知道了,但你是否清楚为什么run方法必须声明成这样的形式?这涉及到JAVA的方法覆盖和重载的规定。这些内容很重要,请读者参考相关资料。

二:关键字synchronized

有了synchronized关键字,多线程程序的运行结果将变得可以控制。synchronized关键字用于保护共享数据。请大家注意"共享数据",你一定要分清哪些数据是共享数据,JAVA是面向对象的程序设计语言,所以初学者在编写多线程程序时,容易分不清哪些数据是共享数据。请看下面的例子:

示例2:

public class ThreadTest implements Runnable
{

public synchronized void run()
{
for(int i=0;i 10;i++)
{
System.out.print(" " + i);
}
}
public static void main(String[] args)
{
Runnable r1 = new ThreadTest();
Runnable r2 = new ThreadTest();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}

在这个程序中,run()被加上了synchronized关键字。在main方法中创建了两个线程。你可能会认为此程序的运行结果一定为:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。但你错了!这个程序中synchronized关键字保护的不是共享数据(其实在这个程序中synchronized关键字没有起到任何作用,此程序的运行结果是不可预先确定的)。这个程序中的t1,t2是两个对象(r1,r2)的线程。JAVA是面向对象的程序设计语言,不同的对象的数据是不同的,r1,r2有各自的run()方法,而synchronized使同一个对象的多个线程,在某个时刻只有其中的一个线程可以访问这个对象的synchronized数据。每个对象都有一个"锁标志",当这个对象的一个线程访问这个对象的某个synchronized数据时,这个对象的所有被synchronized修饰的数据将被上锁(因为"锁标志"被当前线程拿走了),只有当前线程访问完它要访问的synchronized数据时,当前线程才会释放"锁标志",这样同一个对象的其它线程才有机会访问synchronized数据。

示例3:

public class ThreadTest implements Runnable
{
public synchronized void run()
{
for(int i=0;i 10;i++)
{
System.out.print(" " + i);
}
}
public static void main(String[] args)
{
Runnable r = new ThreadTest();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();

t2.start();
}
}

如果你运行1000次这个程序,它的输出结果也一定每次都是:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。因为这里的synchronized保护的是共享数据。t1,t2是同一个对象(r)的两个线程,当其中的一个线程(例如:t1)开始执行run()方法时,由于run()受synchronized保护,所以同一个对象的其他线程(t2)无法访问synchronized方法(run方法)。只有当t1执行完后t2才有机会执行。

示例4:

public class ThreadTest implements Runnable
{
public void run()
{
synchronized(this)
{
for(int i=0;i 10;i++)
{
System.out.print(" " + i);
}
}
}
public static void main(String[] args)
{
Runnable r = new ThreadTest();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}

这个程序与示例3的运行结果一样。在可能的情况下,应该把保护范围缩到最小,可以用示例4的形式,this代表"这个对象"。没有必要把整个run()保护起来,run()中的代码只有一个for循环,所以只要保护for循环就可以了。

示例5:

public class ThreadTest implements Runnable
{
public void run()
{
for(int k=0;k 5;k++)
{
System.out.println(Thread.currentThread().getName()
+ " : for loop : " + k);

}
synchronized(this)
{
for(int k=0;k 5;k++)
{
System.out.println(Thread.currentThread().getName()
+ " : synchronized for loop : " + k);
}
}
}
public static void main(String[] args)
{
Runnable r = new ThreadTest();
Thread t1 = new Thread(r,"t1_name");
Thread t2 = new Thread(r,"t2_name");
t1.start();
t2.start();
}
}
运行结果: t1_name : for loop : 0
t1_name : for loop : 1
t1_name : for loop : 2
t2_name : for loop : 0
t1_name : for loop : 3
t2_name : for loop : 1
t1_name : for loop : 4
t2_name : for loop : 2
t1_name : synchronized for loop : 0
t2_name : for loop : 3
t1_name : synchronized for loop : 1
t2_name : for loop : 4
t1_name : synchronized for loop : 2
t1_name : synchronized for loop : 3
t1_name : synchronized for loop : 4
t2_name : synchronized for loop : 0
t2_name : synchronized for loop : 1
t2_name : synchronized for loop : 2
t2_name : synchronized for loop : 3
t2_name : synchronized for loop : 4

第一个for循环没有受synchronized保护。对于第一个for循环,t1,t2可以同时访问。运行结果表明t1执行到了k=2时,t2开始执行了。t1首先执行完了第一个for循环,此时还没有执行完第一个for循环(t2刚执行到k=2)。t1开始执行第二个for循环,当t1的第二个for循环执行到k=1时,t2的第一个for循环执行完了。t2想开始执行第二个for循环,但由于t1首先执行了第二个for循环,这个对象的锁标志自然在t1手中(synchronized方法的执行权也就落到了t1手中),在t1没执行完第二个for循环的时候,它是不会释放锁标志的。所以t2必须等到t1执行完第二个for循环后,它才可以执行第二个for循环。
三:sleep()

示例6:

public class ThreadTest implements Runnable
{
public void run()
{
for(int k=0;k 5;k++)
{
if(k == 2)
{
try
{
Thread.currentThread().sleep(5000);
}
catch(Exception e)
{}
}
System.out.print(" " + k);
}
}
public static void main(String[] args)
{
Runnable r = new ThreadTest();
Thread t = new Thread(r);
t.start();
}
}

sleep方法会使当前的线程暂停执行一定时间(给其它线程运行机会)。读者可以运行示例6,看看结果就明白了。sleep方法会抛出异常,必须提供捕获代码。

示例7:

public class ThreadTest implements Runnable
{
public void run()
{

for(int k=0;k 5;k++)
{
if(k == 2)
{
try
{
Thread.currentThread().sleep(5000);
}
catch(Exception e)
{}
}
System.out.println(Thread.currentThread().getName()
+ " : " + k);
}
}
public static void main(String[] args)
{
Runnable r = new ThreadTest();
Thread t1 = new Thread(r,"t1_name");
Thread t2 = new Thread(r,"t2_name");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}

t1被设置了最高的优先级,t2被设置了最低的优先级。t1不执行完,t2就没有机会执行。但由于t1在执行的中途休息了5秒中,这使得t2就有机会执行了。读者可以运行这个程序试试看。

示例8:

public class ThreadTest implements Runnable
{
public synchronized void run()
{
for(int k=0;k 5;k++)
{
if(k == 2)
{
try
{
Thread.currentThread().sleep(5000);
}
catch(Exception e)
{}

}
System.out.println(Thread.currentThread().getName()
+ " : " + k);
}
}
public static void main(String[] args)
{
Runnable r = new ThreadTest();
Thread t1 = new Thread(r,"t1_name");
Thread t2 = new Thread(r,"t2_name");
t1.start();
t2.start();
}
}

请读者首先运行示例8程序,从运行结果上看:一个线程在sleep的时候,并不会释放这个对象的锁标志。

展开更多 50%)
分享

猜你喜欢

JAVA专题技术综述之线程篇

编程语言 网络编程
JAVA专题技术综述之线程篇

JAVA技术专题综述之构造方法篇

编程语言 网络编程
JAVA技术专题综述之构造方法篇

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

2004开发技术年度综述之Java世界

Java JAVA基础
2004开发技术年度综述之Java世界

200开发技术年度综述之Windows开发

编程语言 网络编程
200开发技术年度综述之Windows开发

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

浅析Java多线程编程中的高级技术

编程语言 网络编程
浅析Java多线程编程中的高级技术

Java多线程编程精要之基础

Java JAVA基础
Java多线程编程精要之基础

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

C#中一些字符串操作的常用用法

C#中一些字符串操作的常用用法

C#操作注册表的方法

C#操作注册表的方法
下拉加载更多内容 ↓