-------android培训、java培训、期待与您交流! ----------
1.创建线程的方式
(6).不要对已经处于启动的线程再次调用start方法,否则会引起异常
(1).第一种方式:继承Thread类
步骤:
a.定义类继承Thread类
b.重写Thread类中的run方法。(目的:将自定义代码存储在run方法中,让线程运行。)
c.调用线程的start方法,该方法有两个作用:启动线程、调用run方法
示例:
public
class
Ticket
extends
Thread{
private
int
tick
= 100;
public
void
run(){
while
(
tick
>0){
System.
out
.println(Thread. currentThread().getName()+
"..."
+
tick
--);
}
}
public
static
void
main(String[] args) {
Ticket t1 =
new
Ticket();
Ticket t2 =
new
Ticket();
t1.start();
t2.start();
}
}
(2).第二种方式:实现Runnable接口
步骤:
a.定义类实现Runnable接口
b.重写Runnable接口中的run方法
c.通过Thread类建立线程对象
d.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
e.调用Thread类的start方法开启线程并调用Runnable子类的run方法
示例:
public
class
Ticket
implements
Runnable{
private
int
tick
= 100;
public
void
run(){
while
(
tick
>0){
System.
out
.println(Thread. currentThread().getName()+
"..."
+
tick
--);
}
}
public
static
void
main(String[] args) {
Ticket t =
new
Ticket();
new
Thread(t).start();
new
Thread(t).start();
new
Thread(t).start();
}
}
2.两种创建方式的区别
(1).实现接口方式:避免了单继承的局限性。建议使用实现接口的方式。
(2).继承Thread:线程代码存放在Thread子类的run方法中。
实现Runnable:线程代码存放在接口的子类的run方法中。
(3).
使用继承Thread类的方法来创建线程,多条线程之间无法共享线程类的实例变量。使用实现Runnable接口的方式,则可以共享实例变量(重点)。
(4).实现接口方式,如果要访问当前线程,必须要用Thread.currentThread()方法。而继承方式则不需要,直接this即可。
3.一些注意事项
(1).多线程的一个特性:随机性
(2).为什么要重写run方法?
Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。如果不重写的话,Thread中本身的run方法没有什么内容,所以必须重写,使得它运行你自己定义的代码。
(3).线程都有自己的默认名称,为Thread-编号
(4)几个方法:static Thread currentThread():获取当前线程对象
getName():获取线程名称 设置线程名称:setName或者通过构造函数
(5).线程五种状态:新建、就绪、运行、阻塞、死亡
(6).不要对已经处于启动的线程再次调用start方法,否则会引起异常
(7).不要试图对一个已经死亡的线程调用start()方法使它重新启动,否则引起异常。
4.同步代码块
(1).解决安全问题的方法:同步代码块
格式:
synchronized(对象)
{
同步内容
}
注:对象如同锁,持有锁的线程可以在同步中执行。没有持有锁的线程即使获得cpu的准许,也进不去。对象可以为
任何对象。
(2).同步前提:
a.必须要有两个或两个以上的线程。
b.必须是多个线程使用同一个锁。
(3).优点:解决了多线程的安全问题。缺点:多个线程需要判断锁,消耗资源。
(4).如何去找安全问题?
a.明确哪些代码是多线程运行代码
b.明确共享数据
c.明确多线程运行代码中哪些语句是操作共享数据的
5.同步函数
(1).同步函数的锁是:this
(2).静态同步函数的锁不是:this。而是该方法所在类的字节码文件对象。类名.class。
(静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象。类名.class。该类型是Class。)
6.线程间通讯
(1)其实就是多个线程在操纵同一个资源,但操作的的动作不同。
(2).等待唤醒机制:
a.wait()、notify()、notifyAll()都是用在
同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中,因为只有同步才具有锁。
b.为什么这些操纵线程的方法要定义在Object中?
因为这些方法在操作同步中线程时,都必须要标识它们所操作线程持有的锁。只有同一个锁上的被等待的线程,可以被同一个锁上的notify唤醒。不可以对不同锁上的线程进行唤醒。
因为锁是任意对象的,所以被这些对象调用的方法就放在Object中
7.JDK1.5的新特性
1.5中提供了多线程的升级解决方案。将同步synchronized操作替换成了Lock操作。将Object中的wait()、notify()、notifyAll()替换成了Condition对象。该对象可以通过Lock锁进行获取。同时也实现了本方只唤醒对象的操作。
示例:
import
java.util.concurrent.locks.*;
class
Res {
private
String
name
;
private
String
sex
;
private
boolean
flag
=
false
;
private
final
Lock
lock
=
new
ReentrantLock();
private
Condition
con_in
=
lock
.newCondition();
private
Condition
con_ou
=
lock
.newCondition();
public
void
set(String name, String sex)
throws
InterruptedException {
lock
.lock();
try
{
while
(
flag
)
con_in
.await();
this
.
name
= name;
this
.
sex
= sex;
System.
out
.println(Thread. currentThread().getName()+
"...输入..."
+
this
.
name
+
"..."
+
this
.
sex
);
flag
=
true
;
con_ou
.signal();
}
finally
{
lock
.unlock();
}
}
public
void
out()
throws
InterruptedException{
lock
.lock();
try
{
while
(!
flag
)
con_ou
.await();
System.
out
.println(Thread. currentThread().getName()+
"........输出......."
+
this
.
name
+
"..."
+
this
.
sex
);
flag
=
false
;
con_in
.signal();
}
finally
{
lock
.unlock();
}
}
}
class
Iuput
implements
Runnable {
private
Res
r
;
private
int
x
= 0;
public
Iuput(Res r) {
this
.
r
= r;
}
public
void
run() {
try
{
while
(
true
) {
if
(
x
== 0) {
r
.set(
"richard"
,
"man"
);
}
else
{
r
.set(
"flora"
,
"woman"
);
}
x
= (
x
+ 1) % 2;
}
}
catch
(InterruptedException e){
}
}
}
class
Ontput
implements
Runnable {
private
Res
r
;
public
Ontput(Res r) {
this
.
r
= r;
}
public
void
run() {
try
{
while
(
true
)
r
.out();
}
catch
(InterruptedException e){
}
}
}
public
class
TestMain {
public
static
void
main(String[] args) {
Res r =
new
Res();
new
Thread(
new
Iuput(r)).start();
new
Thread(
new
Iuput(r)).start();
new
Thread(
new
Ontput(r)).start();
new
Thread(
new
Ontput(r)).start();
}
}
8.如何停止线程?
以前的stop()已经不能用了,唯一的方法就是使run()方法结束。
开启多线程运行,运行代码通常是循环结构。只要控制住循环就可以让run方法结束,即线程结束。
特殊情况:
当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行时状态中来,这样就可以操作标记让线程结束。
Thread类中提供了该清除冻结的方法:interrupt()方法。
9.一些特殊方法
(1).join():当A线程执行到B线程的join方法时,A就会等待,等B执行完,A才会重新执行。
该方法用来临时加入线程执行。