首先是多线程的一些相关概念:
相关概念:
程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态(指不在执行中)的代码。
进程(process):程序的一次执行过程,或是正在内存中运行的应用程序。
·每个进程都有一个独立的内存空间,系统运行一个程序即是一个进程从创建、运行到消亡的过程。(声明周期)
·程序是静态的,进程是动态的。
·进程作为操作系统调度和分配资源的最小单位(亦是系统运行程序的基本单位),系统在运行时会为每个进程分配不同的内存区域。
线程(thread):进程可以进一步细化为线程,时程序内部的一条执行路径。一个进程中至少有一个线程。
·一个进程同一时间若并行执行多个线程,就是多线程的。
·线程是作为CPU调度和执行的最小单位。
·一个进程中的多个线程共享相同的内存单元,它们从一个堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源就可能会带来安全的隐患。
注:不同的进程之间是不共享内存的。进程之间的数据交换和通信的成本很高。
线程调度:
·分时调度:所有线程轮流使用CPU的使用权,并且平均分配每个线程占用CPU的时间。
·抢占式调度:让优先级高的线程以较大的概率优先使用CPU。如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
多线程程序的优点:
提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
提高计算机系统CPU的利用率。
改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。
并行与并发:
并行(parallel):指两个或多个事件在同一时刻发生。指在同一时刻,有多条指令在多个CPU上同时执行。
并发(concurrency):指两个或多个事件在同一个时间段内发生。即在同一段时间内,有多条指令在单个CPU上快速轮换、交替执行,使得在宏观上具有多个进程同时执行的效果。
Java,多线程,线程创建方式一:继承Thread类
Java语言的JVM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。
Thread类的特性:
①每个线程都是通过某个特定的Thread对象的run( )方法来完成操作的,因此把run( )方法称为线程执行体。
②通过该Thread对象的start( )方法来启动这个线程,而非直接调用run( )方法。
③想要实现多线程,必须在主线程中创建新的线程对象。
通过继承Thread类来创建并启动多线程的步骤如下:
①定义Thread的子类,并重写该类的run( )方法,该run( )方法的方法体就代表了线程需要完成的任务。
②创建Thread类的子类的实例,即创建了线程对象。
③调用线程对象的start( )方法来启动该线程。
start( )的作用:①启动线程②调用当前线程的run( )方法。
以下代码的实现为例:
两个线程分别遍历10000以内的偶数:
public class EvenNumberTest
{
public static void main(String[] args)
{
//③创建当前Thread类的子类的对象
PrintNumber t1 = new PrintNumber();
//通过对象调用start()方法
t1.start();
//main方法所在的线程的执行的操作
for (int i = 1; i <= 10000; i++)
{
if(i % 2 == 0)
{
System.out.println(i + "及你太美");
}
}
}
}
//①创建一个继承于Thread的子类
class PrintNumber extends Thread
{
//②重写Thread类的run方法,并将此线程的要执行的操作,声明在此方法体中
@Override
public void run()
{
for (int i = 1; i <= 10000; i++)
{
if(i % 2 == 0)
{
System.out.println(i);
}
}
}
}
可以发现到两个进程的交替的运行的状况:
注意点一:
如果不调用start( )方法,直接调用run( )方法,便不会开启新的线程。
注意点二:
不能让已经start的线程,再次执行start( ),否则会报异常。正确做法应该是再创建一个新的对象,用新的对象调用start( )方法。
可以利用匿名内部类的方法写出 遍历100以内的奇数和偶数的俩个线程(创建两个匿名内部类(Thread类的子类的匿名)):
class EvenNumber extends Thread
{
@Override
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 0)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
class OddNumber extends Thread
{
@Override
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 1)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
public class PrintNumberTest
{
public static void main(String[] args
{
// EvenNumber e = new EvenNumber();
// OddNumber o = new OddNumber();
// e.start();
// o.start();
//方式二
new Thread(){
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 0)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}.start();
new Thread(){
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 1)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}.start();
}
}
Java,多线程,线程创建方式二:实现Runnable接口
步骤:
①创建一个实现Runnable接口的类
②实现接口中的run( )方法,将此线程要执行的操作,声明在此方法体中。
③创建当前实现类的对象
④将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例。
⑤Thread类的实例调用start( )方法。
基本步骤的样例如下:
//①创建一个实现Runnable接口的类
class EvenNumberPrint implements Runnable
{
//②创建接口中的run()方法,将此线程要执行的操作,声明在此方法体中
@Override
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 0)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
public class EvenNumberTest
{
public static void main(String[] args)
{
EvenNumberPrint e = new EvenNumberPrint();//创建Runnable类的实现类的对象。
Thread thread = new Thread(e);//创建thread类的对象,调用参数为Runnable的实现类的构造器,将实现类的对象代入构造器中去。
thread.start();//直接调用Thread的对象的start方法。
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 1)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
Thread tt = new Thread(e);//要再创建一条新的线程,执行同样的操作,不用再创建实现类的对象,只要再创建Thread的对象就可以,参数用的依然是同一个实现类的对象。
tt.start();
}
}
public class PrintNumberTest
{
public static void main(String[] args)
{
// EvenNumber ee = new EvenNumber();
// OddNumber oo = new OddNumber();
// Thread t1 = new Thread(ee);
// Thread t2 = new Thread(oo);
// t1.start();
// t2.start();
//匿名的Thread的子类,参数为匿名的Runnable的实现类的匿名对象。
new Thread(new Runnable(){
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 0)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}).start();
new Thread(new Runnable(){
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 1)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}).start();
}
}
class EvenNumber implements Runnable
{
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 0)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
class OddNumber implements Runnable
{
@Override
public void run()
{
for (int i = 1; i <= 100; i++)
{
if(i % 2 == 1)
{
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}