进程与线程
1、进程是程序的一次动态执行过程,这个过程也是进程本身从产生到消亡的过程。
2、由于cpu有“分时机制”,所以每个程序都能循环获得cpu的时间片段。加之CPU的执行速度快,感觉上像是同时在运行。
3、多线程是实现并发机制的一种有效手段,线程是比进程更小的执行单位,是进程的基础上进一步的划分。
4、一个进程可能包含多个同时执行的线程。
5、main()函数开始运行的线程为主线程。
6、 在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)。他们之间的区别在于JVM。
7、用户线程:所有用户线程结束,jvm关闭;
8、守护线程:只有守护线程了,jvm可以关闭(也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”)。
9、守护线程是后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程。用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作。
10、通过Thread.setDaemon(false)设置为用户线程,通过Thread.setDaemon(true)设置为守护线程。
线程的生命周期
1、线程创建之后,进入新建状态,jvm给他分配内存空间,并且进行初始化。当线程对象的start()方法被调用,线程就处于可执行状态。
2、处于可执行状态的线程,随时可被CPU调度执行。
3、CPU执行该线程的时候,线程进入执行状态。中间可能会进入阻塞状态或者就绪状态。
4、直至线程异常或者线程正常结束或者return了数据。线程结束,整个生命周期结束。
开启新线程
1、继承Thread类,重写run()方法
class FrozenTread extends Thread {
@Override
public void run(){
dosomething();
}
}
//调用
FrozenTread item = new FrozenTread();
item.start();
2、实现Runnable接口,重写run()
//1):定义一个类A实现于java.lang.Runnable接口,注意A类不是线程类.
class FrozenImplements implements Runnable{
//2):在A类中覆盖Runnable接口中的run方法.
@Override
public void run() {
//3):在run方法中编写需要执行的操作
dosomething();
}
}
//调用
FrozenImplements item = new FrozenImplements();
Thread thread = new Thread(item);
thread.start();
3、直接在函数体使用
//单CPU创建10个线程
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.execute(new Runnable() {
@Override
public void run() {
dosomething();
}
}
pool.shutdown();
while(true){
if(pool.isTerminated()){
break;
}
}
或者
Thread t = new Thread(new Runnable(){
@Override
public void run(){
// run方法具体重写
dosomething();
}});
t.start();
循环插入mysql一万条数据,测试效率
新鲜供测试的数据库
1、常规写法,不开启新线程
public String aaa(){
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
try {
String sql = "insert into ceshi(uuid,test,name,age) values(1234,'22222','2020年7月1日15:46:14',123)";
jdbcTemplate.execute(sql);
}catch (Exception e){
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
String abc= end - start+"毫秒";
System.out.println(abc);
return abc;
}
2、使用ExecutorService,开启10个线程
【拓展】
ExecutorService共有四种线程池:CachedThreadPool可缓存线程池、SingleThreadExecutor单线程池、FixedThreadPool固定线程数线程池、ScheduledThreadPool 固定线程数,支持定时和周期性任务线程池。
public String bbb(){
long start = System.currentTimeMillis();
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
try {
String sql = "insert into ceshi(uuid,test,name,age) values(1234,'22222','哈哈哈多喝点',123)";
jdbcTemplate.execute(sql);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
pool.shutdown();
String abc;
while(true){
if(pool.isTerminated()){//终结者
long end = System.currentTimeMillis();
abc= end - start+"毫秒";
System.out.println(abc);
break;
}
}
return abc;
}
数据成功插入
3、实现java.lang.Runnable接口,开启两个线程
//1):定义一个类A实现于java.lang.Runnable接口,注意A类不是线程类.
class FrozenImplements implements Runnable{
//2):在A类中覆盖Runnable接口中的run方法.
@Override
public void run() {
//3):在run方法中编写需要执行的操作
for (int i = 0; i < 5000; i++) {
try {
String sql = "insert into ceshi(uuid,test,name,age) values(1234,'22222','哈哈哈多喝点',123)";
jdbcTemplate.execute(sql);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public String ddd(){
long start = System.currentTimeMillis();
try {
FrozenImplements item = new FrozenImplements();
Thread thread = new Thread(item);
Thread thread1 = new Thread(item);
thread.start();
thread1.start();
//一个线程在启动后就马上执行,必须调用 Thread.Join()方法
thread.join();
thread1.join();
}catch (Exception e){
e.printStackTrace();
}
long end = System.currentTimeMillis();
return end- start +"毫秒";
}
数据成功插入
效率分析
1、从上面的实现我们可以看出,开启多个线程,表面上执行效率是有所提高。
2、我们的计算机,一般只有一个CPU。多线程只不过是CPU在不同时间片之间的切换和调度。快慢未可知。
3、是不是说开启多个线程,效率就高了或者因为CPU的切换和调度变慢了。这个问题无法给你准确的答案,CPU是和其他硬件设备一起工作的。多线程的目的可以最大限度的提高硬件设备的利用率。
4、也就是说,一个单CPU。多线程是否有效率在于,CPU的效率和其他配合硬件的效率。这是一个不断优化,依照实际情况而定的过程(开启几个线程,是否需要开启线程)。
5、多个cpu的时候,计算机适当多开启几个线程同时处理,会提高效率。
6、服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量