Java多线程初学

多线程

1.1、什么是进程?什么是线程?

进程是一个应用程序(1个进程是一个软件)。
线程是一个进程中的执行场景/执行单元。
一个进程可以启动多个线程。

1.2、对于java程序来说,当在DOS命令窗口中输入:

java HelloWorld 回车之后。
会先启动JVM,而JVM就是一个进程。
JVM再启动一个主线程调用main方法。
同时再启动一个垃圾回收线程负责看护,回收垃圾。
最起码,现在的java程序中至少有两个线程并发,
一个是垃圾回收线程,一个是执行main方法的主线程。

1.3、进程和线程是什么关系?举个例子

阿里巴巴:进程
马云:阿里巴巴的一个线程
童文红:阿里巴巴的一个线程

京东:进程
强东:京东的一个线程
妹妹:京东的一个线程

进程可以看做是现实生活当中的公司。
线程可以看做是公司当中的某个员工。
注意:
进程A和进程B的内存独立不共享。(阿里巴巴和京东资源不会共享的!)
魔兽游戏是一个进程
酷狗音乐是一个进程
这两个进程是独立的,不共享资源。

线程A和线程B呢?
在java语言中:
线程A和线程B,堆内存和方法区内存共享。
但是栈内存独立,一个线程一个栈。

假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,
互不干扰,各自执行各自的,这就是多线程并发。

火车站,可以看做是一个进程。
火车站中的每一个售票窗口可以看做是一个线程。
我在窗口1购票,你可以在窗口2购票,你不需要等我,我也不需要等你。
所以多线程并发可以提高效率。

java中之所以有多线程机制,目的就是为了提高程序的处理效率。

1.4、思考一个问题:

使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束。
main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在
压栈弹栈。

1.5、分析一个问题:对于单核的CPU来说,真的可以做到真正的多线程并发吗?

对于多核的CPU电脑来说,真正的多线程并发是没问题的。
4核CPU表示同一个时间点上,可以真正的有4个进程并发执行。

什么是真正的多线程并发?
t1线程执行t1的。
t2线程执行t2的。
t1不会影响t2,t2也不会影响t1。这叫做真正的多线程并发。
单核的CPU表示只有一个大脑:
不能够做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉。
对于单核的CPU来说,在某一个时间点上实际上只能处理一件事情,但是由于
CPU的处理速度极快,多个线程之间频繁切换执行,跟人来的感觉是:多个事情
同时在做!!!!!
线程A:播放音乐
线程B:运行魔兽游戏
线程A和线程B频繁切换执行,人类会感觉音乐一直在播放,游戏一直在运行,
给我们的感觉是同时并发的。

1.6 第一种创建线程的方法

编写一个类,直接继承java.lang.Thread,重写run方法。

  • 创建线程对象?new就行
  • 怎么启动?调用线程对象run方法
public class ThreadTest02 {

    public static void main(String[] args) {
        这里属于主线程,在主栈种运行。
        新建一个分支线程对象
        MyThread myThread = new MyThread();
        启动线程
        start方法:启动一个分支线程,在JVM开辟一个新的栈空间,完成任务瞬间结束
        栈空间开出来,start就结束,线程启动成功。
        启动成功的线程自动调用run方法,压栈(栈底部)
        run在分支栈底部,main方法在主栈的栈底部。两者平级
        myThread.start();

        这里的代码还是在主线程种
        for(int i=0; i<1000;i++){
            System.out.println("主线程--->" + i);
        }
    }
}

class MyThread extends Thread{
    @Override
    public void run(){
        编写程序,这段运行在分支线程种(分支栈)
        for(int i=0; i<1000;i++){
            System.out.println("分支线程--->" + i);
        }
    }

}

1.7 第二种

实现线程的第二种方式,编写一个类实现java.lang.Runnable接口

public class ThreadTest03 {
    public static void main(String[] args) {
        //创建一个可运行的对象
        MyRunnable r = new MyRunnable();
        //将可运行的对象封装成一个线程对象
        Thread t = new Thread(r);
        //启动线程
        t.start();

        for(int i=0; i<1000;i++){
            System.out.println("主线程--->" + i);
        }
    }
}

//不是一个线程类,还不是一个线程
class MyRunnable implements Runnable{

    @Override
    public void run() {
        for(int i=0; i<1000;i++){
            System.out.println("分支线程--->" + i);
        }
    }
}

也可以用匿名内部类的方式

//匿名内部类实现
public class ThreadTest04 {
    创建线程对象,匿名内部类方式
    通过一个没有名字的类,new出来的对象 这里是一个类,不是一个接口
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i=0; i<100; i++){
                    System.out.println("t线程");
                }
            }
        });

        //启动线程
        t.start();

        for (int i=0; i<100; i++){
            System.out.println("main线程");
        }
    }
}

1.7 获取和修改线程名字 以及当前线程对象

setName getName Thread.currentThread()

public class ThreadTest05 {
    public static void main(String[] args) {

        //这个代码出现在main方法种,所有当前线程就是主线程。
        Thread currentThread = Thread.currentThread();
        System.out.println(currentThread.getName());

        MyThread2 t = new MyThread2();
        t.setName("t1");
        String tName = t.getName();//默认是Thread-0
        System.out.println(tName);

        t.start();

        MyThread2 t2 = new MyThread2();
        t2.setName("t2");
        System.out.println(t2.getName());//默认是Thread-1
        t2.start();
    }
}

class MyThread2 extends Thread{
    public void run(){
        for(int i=0; i<1000;i++){
            //当前线程对象
            Thread currentThread = Thread.currentThread();
            System.out.println(currentThread.getName() + "分支线程--->" + i);
        }
    }

}

线程的sleep方法

线程的sleep方法

  • static void sleep(long millis)
  • 1、静态方法
  • 2、参数是毫秒
  • 3、让当前线程进入休眠,进入“阻塞状态”,放弃所有CPU时间片,让给其他线程。
public class ThreadTest06 {
    public static void main(String[] args) {

        //创建线程
        Thread t = new MyThread3();
        t.setName("t");
        t.start();

        //调用sleep方法
        try {
            t.sleep(5*1000);只会让main线程进入休眠,不会让t睡眠
            执行的时候还是会转化成:Thread.sleep
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        5秒之后这里才会执行
        System.out.println("hello world!");

    }

}

class MyThread3 extends Thread{
    public void run(){
        for(int i=0; i<1000;i++){
            System.out.println(Thread.currentThread().getName() + "--->" + i);
        }
    }
}

叫醒

这里注意 子类重写父类方法,run中的sleep方法只能trycatch 不能抛出异常
因为run在父类中没有抛出异常,所以子类不能比父类抛出更多异常。

这种中断睡眠的方式依靠了java的异常处理机制
t.interrupt();

public class ThreadTest08 {
    public static void main(String[] args) {

       Thread t = new Thread(new MyRunnable2());
       t.setName("t");

       t.start();

       //希望5秒之后,t线程醒来

        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //这种中断睡眠的方式依靠了java的异常处理机制
        t.interrupt();

    }
}

class MyRunnable2 implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "--->begin");
        try {
            //这里注意 子类重写父类方法,只能trycatch 不能抛出异常
            Thread.sleep(1000 * 60 * 60 * 24);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "--->end");
    }
}

终止一个线程

stop可以强行终止线程,会丢失数据,不建议使用。
设一个boolean值,判断一下,如果为false,return就好了

public class ThreadTest09 {
    public static void main(String[] args) {
        MyRunnable3 r = new MyRunnable3();
        Thread t = new Thread(r);
        t.setName("t");
        t.start();

        //模拟5秒
        try {
            Thread.sleep(1000*5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //终止线程
        r.run=false;
    }
}

class MyRunnable3 implements Runnable{

    boolean run = true;

    @Override
    public void run() {
        for(int i=0; i<10; i++){
            if (run){
            System.out.println(Thread.currentThread().getName() + "--->" + i);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            }else {
                //终止当前线程
                return;
            }
        }
    }
}

2、线程的安全问题

2.1、为什么这个是重点?

以后在开发中,我们的项目都是运行在服务器当中,
而服务器已经将线程的定义,线程对象的创建,线程
的启动等,都已经实现完了。这些代码我们都不需要
编写。

最重要的是:你要知道,你编写的程序需要放到一个
多线程的环境下运行,你更需要关注的是这些数据
在多线程并发的环境下是否是安全的。(重点:*****)

2.2、什么时候数据在多线程并发的环境下会存在安全问题呢?

三个条件:
*条件1:多线程并发。
*条件2:有共享数据。
*条件3:共享数据有修改的行为。

	满足以上3个条件之后,就会存在线程安全问题。

2.4、说到线程同步这块,涉及到这两个专业术语:

异步编程模型:

		线程t1和线程t2,各自执行各自的,t1不管t2,t2不管t1,
		谁也不需要等谁,这种编程模型叫做:异步编程模型。
		其实就是:多线程并发(效率较高。)

		异步就是并发。

同步编程模型:

		线程t1和线程t2,在线程t1执行的时候,必须等待t2线程执行
		结束,或者说在t2线程执行的时候,必须等待t1线程执行结束,
		两个线程之间发生了等待关系,这就是同步编程模型。
		效率较低。线程排队执行。

		同步就是排队。

实例

关于锁机制
synchronized后面小括号中传的这个“数据”是相当关键的。
这个数据必须是多线程共享的数据。才能达到多线程排队。

        ()中写什么?
            那要看你想让哪些线程同步。
            假设t1、t2、t3、t4、t5,有5个线程,
            你只希望t1 t2 t3排队,t4 t5不需要排队。怎么办?
            你一定要在()中写一个t1 t2 t3共享的对象。而这个
            对象对于t4 t5来说不是共享的。

        这里的共享对象是:账户对象。
        账户对象是共享的,那么this就是账户对象吧!!!
        不一定是this,这里只要是多线程共享的那个对象就行。

        在java语言中,任何一个对象都有“一把锁”,其实这把锁就是标记。(只是把它叫做锁。)
        100个对象,100把锁。1个对象1把锁。

        以下代码的执行原理?
            1、假设t1和t2线程并发,开始执行以下代码的时候,肯定有一个先一个后。
            2、假设t1先执行了,遇到了synchronized,这个时候自动找“后面共享对象”的对象锁,
            找到之后,并占有这把锁,然后执行同步代码块中的程序,在程序执行过程中一直都是
            占有这把锁的。直到同步代码块代码结束,这把锁才会释放。
            3、假设t1已经占有这把锁,此时t2也遇到synchronized关键字,也会去占有后面
            共享对象的这把锁,结果这把锁被t1占有,t2只能在同步代码块外面等待t1的结束,
            直到t1把同步代码块执行结束了,t1会归还这把锁,此时t2终于等到这把锁,然后
            t2占有这把锁之后,进入同步代码块执行程序。

            这样就达到了线程排队执行。
            这里需要注意的是:这个共享对象一定要选好了。这个共享对象一定是你需要排队
            执行的这些线程对象所共享的。

账户类
这里synchronized放this obj 字符串都可以,因为都是t1、t2共享的

package com.bjpowernode.java.threadsafe;

//银行账户

public class Account {
    //账号
    private String actno;
    //余额
    private double balance;

    public Account() {
    }

    public Account(String actno, double balance) {
        this.actno = actno;
        this.balance = balance;
    }

    public String getActno() {
        return actno;
    }

    public void setActno(String actno) {
        this.actno = actno;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    //对象
    Object obj = new Object(); // 实例变量。(Account对象是多线程共享的,Account对象中的实例变量obj也是共享的。)


    //取款方法
    public void withdraw(double money){
        //t1和t2并发这个方法。。。(两个栈,操作堆中同一个对象)

        //线程同步 传入的数据必须是多线程共享的数据,才能达到多线程排队

        //synchronized (this){
        //synchronized (obj){
        synchronized ("abc"){//字符串常量池中,只有一个
            //取款之前的余额
            double before = this.getBalance();
            //取款之后的余额
            double after = before - money;

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


            //更新余额
            //t1执行到这里,还没来得及执行这行代码更新,t2线程进来withdraw方法了,此时一定出问题
            this.setBalance(after);
        }

    }
}

线程类

public class AccountThread extends Thread {
    //两个线程必须共享同一个账户对象。
    private Account act;

    public AccountThread(Account act) {
        this.act = act;
    }

    public void run(){
        //run方法的执行表示取款操作。
        //取款5000
        double money = 5000;
        act.withdraw(5000);


        System.out.println(Thread.currentThread().getName() + "对"+act.getActno()+"取款成功,余额" + act.getBalance());
    }
}

测试

public class Test {
    public static void main(String[] args) {
        //创建账户对象
        Account act = new Account("act-001",10000);
        //两个线程
        Thread t1 = new AccountThread(act);
        Thread t2 = new AccountThread(act);
        //设置name
        t1.setName("t1");
        t2.setName("t2");
        //启动线程取款
        t1.start();
        t2.start();

    }
}

注意synchronized 锁也可以写在run方法里,都是一样的。
但是这样扩大了同步的范围,效率更低了
这里不能写this,代表的是线程类AccountThread

public void run(){
        //run方法的执行表示取款操作。
        //取款5000
        double money = 5000;
        synchronized (act){
            act.withdraw(5000);
        }
       


        System.out.println(Thread.currentThread().getName() + "对"+act.getActno()+"取款成功,余额" + act.getBalance());
    }

还可以写在实例方法上
将账户Account类withdraw方法改为
出现在实例方法上,一定锁的是this 不灵活,不建议,但有用

//出现在实例方法上,一定锁的是this 不灵活
    public synchronized void withdraw(double money){


            double before = this.getBalance();
            double after = before - money;

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            this.setBalance(after);
        }

    }

3、Java中有三大变量?【重要的内容。】

实例变量:在堆中。

静态变量:在方法区。

局部变量:在栈中。

以上三大变量中:
	局部变量永远都不会存在线程安全问题。
	因为局部变量不共享。(一个线程一个栈。)
	局部变量在栈中。所以局部变量永远都不会共享。

实例变量在堆中,堆只有1个。
静态变量在方法区中,方法区只有1个。
堆和方法区都是多线程共享的,所以可能存在线程安全问题。

局部变量+常量:不会有线程安全问题。
成员变量:可能会有线程安全问题。

4、如果使用局部变量的话:

建议使用:StringBuilder。
因为局部变量不存在线程安全问题。选择StringBuilder。
StringBuffer效率比较低。

ArrayList是非线程安全的。
Vector是线程安全的。
HashMap HashSet是非线程安全的。
Hashtable是线程安全的。

5、总结:

synchronized有三种写法:

	第一种:同步代码块
		灵活
		synchronized(线程共享对象){
			同步代码块;
		}

	第二种:在实例方法上使用synchronized
		表示共享对象一定是this
		并且同步代码块是整个方法体。
	
	第三种:在静态方法上使用synchronized
		表示找类锁。
		类锁永远只有1把。
		就算创建了100个对象,那类锁也只有一把。
	
	对象锁:1个对象1把锁,100个对象100把锁。
	类锁:100个对象,也可能只是1把类锁。

小练习

doOther方法执行时需要等待doSome方法的结束吗?

不需要,因为doOther()方法没有synchronized
public class Exam01 {

    public static void main(String[] args) throws InterruptedException {
        MyClass mc = new MyClass();

        Thread t1 = new MyThread(mc);
        Thread t2 = new MyThread(mc);

        t1.setName("t1");
        t2.setName("t2");

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }

}

class MyThread extends Thread{

    private MyClass mc;
    public  MyThread(MyClass mc){
        this.mc = mc;
    }

    public void run(){
        if(Thread.currentThread().getName().equals("t1")){
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")){
            mc.doOther();
        }
    }

}

class MyClass{
    public synchronized void doSome(){
        System.out.println("doSome begin");

        try {
            Thread.sleep(1000 * 10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }

    public void doOther(){
        System.out.println("doOther begin");
        System.out.println("doOther end");
    }
}
需要 synchronized出现在静态方法上是类锁,不管创建几个对象,锁只有一把
public class Exam01 {

    public static void main(String[] args) throws InterruptedException {
        MyClass mc1 = new MyClass();
        MyClass mc2 = new MyClass();

        Thread t1 = new MyThread(mc1);
        Thread t2 = new MyThread(mc2);

        t1.setName("t1");
        t2.setName("t2");

        t1.start();
        Thread.sleep(1000);
        t2.start();
    }

}

class MyThread extends Thread{

    private MyClass mc;
    public  MyThread(MyClass mc){
        this.mc = mc;
    }

    public void run(){
        if(Thread.currentThread().getName().equals("t1")){
            mc.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")){
            mc.doOther();
        }
    }

}

class MyClass{
    public synchronized static void doSome(){
        System.out.println("doSome begin");

        try {
            Thread.sleep(1000 * 10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over");
    }

    public synchronized static void doOther(){
        System.out.println("doOther begin");
        System.out.println("doOther end");
    }
}

死锁

开发中synchronized最好不要嵌套使用

public class DeadLock {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();

        //t1 t2两个线程共享o1 o2
        Thread t1 = new MyThread1(o1,o2);
        Thread t2 = new MyThread2(o1,o2);
    }
}

class MyThread1 extends Thread{
    Object o1;
    Object o2;

    public MyThread1(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }

    public void run(){
        synchronized (o1){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (o2){
                这块代码结束,锁才取消,然而锁o2的时候,o2被占用了
            }
        }
    }
}

class MyThread2 extends Thread{
    Object o1;
    Object o2;

    public MyThread2(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }

    public void run(){
        synchronized (o2){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o1){
            锁o1的时候,o1被占用了
            }
        }
    }
}

6、聊一聊,我们以后开发中应该怎么解决线程安全问题?

是一上来就选择线程同步吗?synchronized
	不是,synchronized会让程序的执行效率降低,用户体验不好。
	系统的用户吞吐量降低。用户体验差。在不得已的情况下再选择
	线程同步机制。

第一种方案:尽量使用局部变量代替“实例变量和静态变量”。

第二种方案:如果必须是实例变量,那么可以考虑创建多个对象,这样
实例变量的内存就不共享了。(一个线程对应1个对象,100个线程对应100个对象,
对象不共享,就没有数据安全问题了。)

第三种方案:如果不能使用局部变量,对象也不能创建多个,这个时候
就只能选择synchronized了。线程同步机制。

守护线程

java语言中线程分为两大类:
一类是:用户线程
一类是:守护线程(后台线程)
其中具有代表性的就是:垃圾回收线程(守护线程)。

	守护线程的特点:
		一般守护线程是一个死循环,所有的用户线程只要结束,
		守护线程自动结束。
	
	注意:主线程main方法是一个用户线程。

	守护线程用在什么地方呢?
		每天00:00的时候系统数据自动备份。
		这个需要使用到定时器,并且我们可以将定时器设置为守护线程。
		一直在那里看着,没到00:00的时候就备份一次。所有的用户线程
		如果结束了,守护线程自动退出,没有必要进行数据备份了。
public class test {
    public static void main(String[] args) {
        Thread t = new BakDataThread();
        t.setName("备份数据的线程");
        设置为守护线程,主线程结束,守护就结束了
        t.setDaemon(true);
        t.start();

        //主线程:这是用户线程
        for (int i=0; i<10; i++){
            System.out.println(Thread.currentThread().getName() + "--->" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class BakDataThread extends Thread{
    public void run(){
        int i = 0;
        while (true){
            System.out.println(Thread.currentThread().getName() + "--->" +(++i));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

定时器

定时器的作用:
间隔特定的时间,执行特定的程序。

		每周要进行银行账户的总账操作。
		每天要进行数据的备份操作。

		在实际的开发中,每隔多久执行一段特定的程序,这种需求是很常见的,
		那么在java中其实可以采用多种方式实现:
			
			可以使用sleep方法,睡眠,设置睡眠时间,没到这个时间点醒来,执行
			任务。这种方式是最原始的定时器。(比较low)

			在java的类库中已经写好了一个定时器:java.util.Timer,可以直接拿来用。
			不过,这种方式在目前的开发中也很少用,因为现在有很多高级框架都是支持
			定时任务的。

			在实际的开发中,目前使用较多的是Spring框架中提供的SpringTask框架,
			这个框架只要进行简单的配置,就可以完成定时器的任务。
public class TimeTest {
    public static void main(String[] args) throws ParseException {
        //创建定时器对象
        Timer timer = new Timer();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date firstTime = sdf.parse("2020-06-03 20:20:00");
        timer.schedule(new LogTimerTask(),firstTime,1000*10);
    }
}

class LogTimerTask extends TimerTask{

    @Override
    public void run() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String strTime = sdf.format(new Date());
        System.out.println(strTime + ":成功完成了一次数据备份!");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值