20171016-进程、线程问题
====================程序、进程、线程的概念==================
1.程序、进程、线程之间的区别?
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
程序预热:
首先要明白,如下的程序是不是多线程?
public class MultiThread {
public static void main(String[] args) {
method2();
}
public static void method1(){
System.out.println("Method1执行了!");
}
public static void method2(){
System.out.println("Method2执行了!");
method1();
}
}
Java中多线程的创建和使用
继承Thread类与实现Runnable接口
1.继承Thread类
//1实现多线程的第一种方式,继承Thread类
class SubThread extends Thread{
//需要重写Run方法
public void run() {
for(int i = 0 ;i <100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class MultiThread {
public static void main(String[] args) {
SubThread subThread = new SubThread();
//开启线程
//同一个子线程只能被调用一次!
subThread.start();
for(int i = 0 ;i <100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
用继承Thread类的方式实现多窗口售票的功能
//1模拟火车站售票窗口,开启三个窗口售票,总票数为100张
class Window extends Thread{
private static int ticket = 100;
【非静态的属性是不能被多个线程共用的!】
public void run(){
while(ticket > 0){
System.out.println(Thread.currentThread().getName()+" 所售票号为:"+(ticket--));
}
}
}
public class MultiThread {
public static void main(String[] args) {
Window w1 = new Window();
Window w2 = new Window();
Window w3 = new Window();
w1.start();
w2.start();
w3.start();
}
}
多线程的第二种实现方式:实现接口的方式
//2.实现线程的第二种方式,实现接口的方式
class SubThread implements Runnable{
@Override public void run() {
for(int i=0 ;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class MultiThread {
public static void main(String[] args) {
SubThread s1 = new SubThread();
Thread t1 = new Thread(s1);
Thread t2 = new Thread(s1);
t1.start();
t2.start();
}
}
//模拟窗口卖票.实现线程的第二种方式,实现接口的方式
class SubThread implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(ticket >0){
System.out.println(Thread.currentThread().getName()+"所出售的票是:"+(ticket--));
}
}
}
public class MultiThread {
public static void main(String[] args) {
SubThread s1 = new SubThread();
Thread t1 = new Thread(s1);
Thread t2 = new Thread(s1);
t1.start();
t2.start();
}
}
对比: 继承Thread类与实现Runnable接口的方式,哪个实现方式更好一些呢? 实现的方式更优雅一些:
①:避免了java单继承的局限性
②: 如果多个线程要操作同一份资源(或数据).更适合使用实现的方式。
====================多线程安全问题【演示】========================
//此程序存在线程安全问题,存在重票或者错票的问题!
class SubThread implements Runnable{
private int ticket = 100;
@Override public void run() {
while(ticket >0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"所出售的票是:"+(ticket--));
}
}
}
public class MultiThread {
public static void main(String[] args) {
SubThread s1 = new SubThread();
Thread t1 = new Thread(s1);
Thread t2 = new Thread(s1);
t1.start();
t2.start();
}
}
//那怎么处理线程安全的问题呢?
1.首先要知道出现线程安全问题的原因是什么?
由于一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在了安全问题。
2.如何来解决线程的安全问题?
必须让一个线程操作共享数据完毕之后,其它线程才有机会参与共享数据的操作!
3.Java如何实现线程的安全:线程的同步机制
方式一:同步代码块[参考doc文档]
方式二:同步方法[默认的锁对象是this关键字
]