1.
程序、进程、线程的理解
程序
(program):
一段静态的代码,
为完成特定任务、用某种语言编写的一组指令的集合。
进程
(process):
程序的一次执行过程,或是
正在运行的一个程序
。
线程
(thread):
进程可进一步细化为线程,是一个程序内部的一条执行路经。
2.
创建多线程的四种方式
方式一:继承
Thread
类的方式:
* 1.
提供一个继承于
Thread
类的子类
* 2.
重写
Thread
类的
run():
将创建的线程要执行的操作,声明在
run()
中。
* 3.
实例化
Thread
子类
* 4.
调用子类对象的
start():
①
启动线程
②
调用当前线程的
run()
说明两个问题:
1.
能不能直接调用
run()
,去启动分线程?不能!
2.
如何启动第二个分线程,必须重新创建一个
Thread
子类对象,不能使用原有的第一个
Thread
对象再次
start()
方式二:实现
Runnable
接口的方式:
* 1.
创建一个实现
Runnable
接口的类
* 2.
实现
Runnable
中的
run()
* 3.
创建当前实现类的对象
* 4.
将此对象作为参数传递到
Thread
类的构造器中,创建
Thread
类的对象
* 5.
通过
Thread
类的对象调用其
start()
两种方式的对比:
* 1.
联系:
public class Thread implements Runnable
* 2.
相同点:启动线程,使用的是同一个
start()
方法
*
* 3.
对比:实现
Runnable
接口更好一些。
*
原因:
1
不影响类的继承。因为类是单继承的。
* 2
针对于共享数据的操作,更适合使用
Runnable
的方式。
*
换句话说,实现
Runnable
接口的方式,实现了代码和数据的分离。
*************************
方式三:实现
Callable
接口
(
jdk1.5
以后)
class
MyThread03
implements
Callable<Integer> {
@Override
public
Integer
call
()
throws
Exception {
System.
out
.println(
"-----MyThread03"
);
return
200;
}
}
main(){
FutureTask
futureTask
=
new
FutureTask(
new
MyThread03())
;
new
Thread(
futureTask
).start();
}
优点:
①
分线程执行的方法,可以有返回值
②
执行的方法可以抛出异常的。
方式四:
使用线程池
//
创建并使用多线程的第四种方法:使用线程池
class
MyThread
implements
Runnable {
@Override
public
void
run() {
for
(
int
i
= 1;
i
<= 100;
i
++) {
System.
out
.println(Thread.
currentThread
().getName() +
":"
+
i
);
}
}
}
public
class
ThreadPool {
public
static
void
main(String[]
args
) {
//1.
调用
Executors
的
newFixedThreadPool(),
返回指定线程数量的
ExecutorService
ExecutorService
pool
= Executors.
newFixedThreadPool
(10);
//2.
将
Runnable
实现类的对象作为形参传递给
ExecutorService
的
submit()
方法中,开启线程
//
并执行相关的
run()
pool
.submit(
new
MyThread());
//
线程
.start()
pool
.submit(
new
MyThread());
pool
.submit(
new
MyThread());
//3.
结束线程的使用
pool
.shutdown();
}
}
3.
Thread
类中的常用方法
1.run():Thread
的子类一定要重写的方法。将此分线程要执行的操作,声明在
run()
中
* 2.start():
要想启动一个分线程,就需要调用
start():①
启动线程
②
调用线程的
run()
* 3.currentThread():
静态方法,获取当前的线程
* 4.getName():
获取当前线程的名字
* 5.setName(String name)
:设置当前线程的名字
* 6.yield():
当前线程调用此方法,释放
CPU
的执行权
* 7.join():
在线程
a
中调用线程
b
的
join()
方法
:
只用当线程
b
执行结束以后,线程
a
结束阻塞状态,继续执行。
* 8.sleep(long
millitimes
):
让当前的线程睡眠
millitimes
毫秒
* 9.isAlive():
判断当前线程是否存活
* 10.
线程的优先级:
* MAX_PRIORITY
:
10
* NORM_PRIORITY
:
5
---
默认优先级
* MIN_PRIORITY
:
1
*
*
设置优先级:
setPriority(
int
priority);
*
获取优先级:
getPriority();
*
*
设置优先级以后,对高优先级,使用优先调度的抢占式策略,抢占低优先级的执行。但是并不意味着高优先级的线程一定先于低优先级的线程执行,而是从概率上来讲,概率更大而已。
*************************************
*
线程通信:
wait() / notify() / notifyAll()
---->
java.lang.Object
类中定义的方法
4. Thread
的生命周期
5.
死锁问题
1
)
.
死锁的理解:
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
2
)
.
说明:
死锁,是我们开发中需要规避的!
3
)
.
举例:
public
class
DeadLockTest {
public
static
void
main(String[]
args
) {
StringBuffer
s1
=
new
StringBuffer();
StringBuffer
s2
=
new
StringBuffer();
new
Thread(
new
Runnable() {
public
void
run() {
synchronized
(
s1
) {
s1
.append(
"a"
);
//
类似
s += "a"
s2
.append(
"1"
);
try
{
Thread.
sleep
(10);
}
catch
(InterruptedException
e
) {
e
.printStackTrace();
}
synchronized
(
s2
) {
s1
.append(
"b"
);
s2
.append(
"2"
);
System.
out
.println(
s1
);
System.
out
.println(
s2
);
}
}
}
}).start();
new
Thread(
new
Runnable() {
public
void
run() {
synchronized
(
s2
) {
s1
.append(
"c"
);
//
类似
s += "a"
s2
.append(
"3"
);
try
{
Thread.
sleep
(10);
}
catch
(InterruptedException
e
) {
e
.printStackTrace();
}
synchronized
(
s1
) {
s1
.append(
"d"
);
s2
.append(
"4"
);
System.
out
.println(
s1
);
System.
out
.println(
s2
);
}
}
}
}).start();
}
}
7.sleep()与wait()的区别
* 1.方法声明在哪? Thread:sleep() Object:wait()
* 2.共同点:使得当前线程进入阻塞状态
* 3.使用的范围要求:sleep()使用没情境的要求;wait()必须使用在同步代码块或同步方法中
* 4.都使用在同步当中的话:wait()需要唤醒:notify()/notifyAll(); sleep():不会释放锁;wait()会释放锁
* 5.sleep是static方法,而wait是成员方法,