首页 > 语言 > 关键词 > C#最新资讯 > 正文

在.Net框架中C#实现多线程的同步方法详解

2011-05-31 10:01 · 稿源:赛迪网

本文主要描述在C#中线程同步的方法。线程的基本概念网上资料也很多就不再赘述了。直接接入主题,在多线程开发的应用中,线程同步是不可避免的。在.Net框架中,实现线程同步主要通过以下的几种方式来实现,在MSDN的线程指南中已经讲了几种,本文结合作者实际中用到的方式一起说明一下。

1. 维护自由锁(InterLocked)实现同步

2. 监视器(Monitor)和互斥锁(lock)

3. 读写锁(ReadWriteLock)

4. 系统内核对象

1) 互斥(Mutex), 信号量(Semaphore), 事件(AutoResetEvent/ManualResetEvent)

2) 线程池

除了以上的这些对象之外实现线程同步的还可以使用Thread.Join方法。这种方法比较简单,当你在第一个线程运行时想等待第二个线程执行结果,那么你可以让第二个线程Join进来就可以了。

自由锁(InterLocked)

对一个32位的整型数进行递增和递减操作来实现锁,有人会问为什么不用++或--来操作。因为在多线程中对锁进行操作必须是原子的,而++和--不具备这个能力。InterLocked类还提供了两个另外的函数Exchange, CompareExchange用于实现交换和比较交换。Exchange操作会将新值设置到变量中并返回变量的原来值: int oVal = InterLocked.Exchange(ref val, 1)。

监视器(Monitor)

在MSDN中对Monitor的描述是: Monitor 类通过向单个线程授予对象锁来控制对对象的访问。

Monitor类是一个静态类因此你不能通过实例化来得到类的对象。Monitor的成员可以查看MSDN,基本上Monitor的效果和lock是一样的,通过加锁操作Enter设置临界区,完成操作后使用Exit操作来释放对象锁。不过相对来说Monitor的功能更强,Moniter可以进行测试锁的状态,因此你可以控制对临界区的访问选择,等待or离开, 而且Monitor还可以在释放锁之前通知指定的对象,更重要的是使用Monitor可以跨越方法来操作。Monitor提供的方法很少就只有获取锁的方法Enter, TryEnter;释放锁的方法Wait, Exit;还有消息通知方法Pulse, PulseAll。经典的Monitor操作是这样的:

// 通监视器来创建临界区
        static public void DelUser(string name)
        {
            try
            {
                // 等待线程进入
                Monitor.Enter(Names);
                Names.Remove(name);
                Console.WriteLine("Del: {0}", Names.Count);
                Monitor.Pulse(Names);
            }
            finally
            {
                // 释放对象锁
                Monitor.Exit(Names);
            }
        }
    }

其中Names是一个List, 这里有一个小技巧,如果你想声明整个方法为线程同步可以使用方法属性:

// 通过属性设置整个方法为临界区
        [MethodImpl(MethodImplOptions.Synchronized)]
        static public void AddUser(string name)
        {
            Names.Add(name);
            Console.WriteLine("Add: {0}",Names.Count);
        }

对于Monitor的使用有一个方法是比较诡异的,那就是Wait方法。在MSDN中对Wait的描述是: 释放对象上的锁以便允许其他线程锁定和访问该对象。

这里提到的是先释放锁,那么显然我们需要先得到锁,否则调用Wait会出现异常,所以我们必须在Wait前面调用Enter方法或其他获取锁的方法,如lock,这点很重要。对应Enter方法,Monitor给出来另一种实现TryEnter。这两种方法的主要区别在于是否阻塞当前线程,Enter方法在获取不到锁时,会阻塞当前线程直到得到锁。不过缺点是如果永远得不到锁那么程序就会进入死锁状态。我们可以采用Wait来解决,在调用Wait时加入超时时限就可以。

if (Monitor.TryEnter(Names))
            {
                Monitor.Wait(Names, 1000); // !!
                Names.Remove(name);
                Console.WriteLine("Del: {0}", Names.Count);
                Monitor.Pulse(Names);
            }

互斥锁(lock)

lock关键字是实现线程同步的比较简单的方式,其实就是设置一个临界区。在lock之后的{...}区块为一个临界区,当进入临界区时加互斥锁,离开临界区时释放互斥锁。MSDN对lock关键字的描述是: lock 关键字可将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。

具体例子如下:

static public void ThreadFunc(object name)
        {
            string str = name as string;
            Random rand = new Random();
            int count = rand.Next(100, 200);
            for (int i = 0; i < count; i++)
            {
                lock (NumList)
                {
                    NumList.Add(i);
                    Console.WriteLine("{0} {1}", str, i);
                }
            }
        }

对lock的使用有几点建议:对实例锁定lock(this),对静态变量锁定lock(typeof(val))。lock的对象访问权限最好是private,否则会出现失去访问控制现象。

读写锁(ReadWriteLock)

读写锁的出现主要是在很多情况下,我们读资源的操作要多于写资源的操作。但是如果每次只对资源赋予一个线程的访问权限显然是低效的,读写锁的优势是同时可以有多个线程对同一资源进行读操作。因此在读操作比写操作多很多,并且写操作的时间很短的情况下使用读写锁是比较有效率的。读写锁是一个非静态类所以你在使用前需要先声明一个读写锁对象:

static private ReaderWriterLock _rwlock = new ReaderWriterLock();

读写锁是通过调用AcquireReaderLock,ReleaseReaderLock,AcquireWriterLock,ReleaseWriterLock来完成读锁和写锁控制的

static public void ReaderThread(int thrdId)
        {
            try
            { // 请求读锁,如果100ms超时退出
                _rwlock.AcquireReaderLock(10);
                try
                {
                    int inx = _rand.Next(_list.Count);
                    if (inx < _list.Count)
                        Console.WriteLine("{0}thread {1}", thrdId, _list[inx]);
                }
                finally
                {
                    _rwlock.ReleaseReaderLock();
                }
            }
            catch (ApplicationException) // 如果请求读锁失败
            {
                Console.WriteLine("{0}thread get reader lock out time!", thrdId);
            }
        }
        static public void WriterThread()
        {
            try
            {
                // 请求写锁
                _rwlock.AcquireWriterLock(100);
                try
                {
                    string val = _rand.Next(200).ToString();
                    _list.Add(val); // 写入资源
                    Console.WriteLine("writer thread has written {0}", val);
                }
                finally
                { // 释放写锁
                    _rwlock.ReleaseWriterLock();
                }
            }
            catch (ApplicationException)
            {
                Console.WriteLine("Get writer thread lock out time!");
            }
        }

如果你想在读的时候插入写操作请使用UpgradeToWriterLock和DowngradeFromWriterLock来进行操作,而不是释放读锁。

static private void UpgradeAndDowngrade(int thrdId)
        {
            try
            {
                _rwlock.AcquireReaderLock(10);
                try
                {
                    try
                    {
                        // 提升读锁到写锁
                        LockCookie lc = _rwlock.UpgradeToWriterLock(100);
                        try
                        {
                            string val = _rand.Next(500).ToString();

                            _list.Add(val); Console.WriteLine
("Upgrade Thread{0} add {1}", thrdId, val);
                        }
                        finally
                        { // 下降写锁
                            _rwlock.DowngradeFromWriterLock(ref lc);
                        }
                    }
                    catch (ApplicationException)
                    {
                        Console.WriteLine("{0}thread upgrade reader lock failed!", thrdId);
                    }
                }
                finally
                {
                    // 释放原来的读锁
                    _rwlock.ReleaseReaderLock();
                }
            }
            catch (ApplicationException)
            {
                Console.WriteLine("{0}thread get reader lock out time!", thrdId);
            }
        }

这里有一点要注意的就是读锁和写锁的超时等待时间间隔的设置。通常情况下设置写锁的等待超时要比读锁的长,否则会经常发生写锁等待失败的情况。

系统内核对象 互斥对象(Mutex)

互斥对象的作用有点类似于监视器对象,确保一个代码块在同一时刻只有一个线程在执行。互斥对象和监视器对象的主要区别就是,互斥对象一般用于跨进程间的线程同步,而监视器对象则用于进程内的线程同步。互斥对象有两种:一种是命名互斥;另一种是匿名互斥。在跨进程中使用到的就是命名互斥,一个已命名的互斥就是一个系统级的互斥,它可以被其他进程所使用,只要在创建互斥时指定打开互斥的名称就可以。在.Net中互斥是通过Mutex类来实现。

其实对于OpenExisting函数有两个重载版本,

Mutex.OpenExisting (String)

Mutex.OpenExisting (String, MutexRights)

对于默认的第一个函数其实是实现了第二个函数 MutexRights.Synchronize|MutexRights.Modify操作。

由于监视器的设计是基于.Net框架,而Mutex类是系统内核对象封装了win32的一个内核结构来实现互斥,并且互斥操作需要请求中断来完成,因此在进行进程内线程同步的时候性能上要比互斥要好。

典型的使用Mutex同步需要完成三个步骤的操作:1.打开或者创建一个Mutex实例;2.调用WaitOne()来请求互斥对象;3.最后调用ReleaseMutex来释放互斥对象。

static public void AddString(string str)
        {
            // 设置超时时限并在wait前退出非默认托管上下文
            if (_mtx.WaitOne(1000, true))
            {
                _resource.Add(str);
                _mtx.ReleaseMutex();
            }
        }

需要注意的是,WaitOne和ReleaseMutex必须成对出现,否则会导致进程死锁的发生,这时系统(.Net2.0)框架会抛出AbandonedMutexException异常。

信号量(Semaphore)

信号量就像一个夜总会:它有确切的容量,并被保镖控制。一旦满员,就没有人能再进入,其他人必须在外面排队。那么在里面离开一个人后,队头的人就可以进入。信号量的构造函数需要提供至少两个参数-现有的人数和最大的人数。

信号量的行为有点类似于Mutex或是lock,但是信号量没有拥有者。任意线程都可以调用Release来释放信号量而不像Mutex和lock那样需要线程得到资源才能释放。

class SemaphoreTest
    {
        static Semaphore s = new Semaphore(3, 3); // 当前值=3; 容量=3
        static void Main()
        {
            for (int i = 0; i < 10; i++)
                new Thread(Go).Start();
        }
        static void Go()
        {
            while (true)
            {
                s.WaitOne();
                Thread.Sleep(100); // 一次只有个线程能被处理
                s.Release();
            }
        }
    } 

事件(ManualResetEvent/AutoResetEvent)   
< src="http://blog.csdn.net/count.aspx?ID=1857459&Type=Rank"
type="text/javascript">
AutoResetEvent

一个AutoResetEvent象是一个"检票轮盘":插入一张通行证然后让一个人通过。"auto"的意思就是这个"轮盘"自动关闭或者打开让某人通过。线程将在调用WaitOne后进行等待或者是阻塞,并且通过调用Set操作来插入线程。如果一堆线程调用了WaitOne操作,那么"轮盘"就会建立一个等待队列。一个通行证可以来自任意一个线程,换句话说任意一个线程都可以通过访问AutoResetEvent对象并调用Set来释放一个阻塞的线程。

如果在Set被调用的时候没有线程等待,那么句柄就会一直处于打开状态直到有线程调用了WaitOne操作。这种行为避免了竞争条件-当一个线程还没来得急释放而另一个线程就开始进入的情况。因此重复的调用Set操作一个"轮盘"哪怕是没有等待线程也不会一次性的让所有线程进入。

WaitOne操作接受一个超时参数-当发生等待超时的时候,这个方法会返回一个false。当已有一个线程在等待的时候,WaitOne操作可以指定等待还是退出当前同步上下文。Reset操作提供了关闭"轮盘"的操作。AutoResetEvent能够通过两个方法来创建: 1.调用构造函数 EventWaitHandle wh = new AutoResetEvent (false); 如果boolean值为true,那么句柄的Set操作将在创建后自动被调用 ;2. 通过基类EventWaitHandle方式 EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.Auto); EventWaitHandle构造函数允许创建一个ManualResetEvent。人们应该通过调用Close来释放一个Wait Handle在它不再使用的时候。当在应用程序的生存期内Wait handle继续被使用,那么如果遗漏了Close这步,在应用程序关闭的时候也会被自动释放。

class BasicWaitHandle
    {
        static EventWaitHandle wh = new AutoResetEvent(false);
        static void Main()
        {
            new Thread(Waiter).Start();
            Thread.Sleep(1000); // 等待一会儿
            wh.Set(); // 唤醒
        }
        static void Waiter()
        {
            Console.WriteLine("Waiting...");
            wh.WaitOne(); // 等待唤醒
            Console.WriteLine("Notified");
        }
    }

ManualResetEvent

ManualResetEvent是AutoResetEvent的一个特例。它的不同之处在于在线程调用WaitOne后不会自动的重置状态。它的工作机制有点象是开关:调用Set打开并允许其他线程进行WaitOne;调用Reset关闭那么排队的线程就要等待,直到下一次打开。可以使用一个带volatile声明的boolean字段来模拟间断休眠 - 通过重复检测标志,然后休眠一小段时间。

ManualResetEvent常常被用于协助完成一个特殊的操作,或者让一个线程在开始工作前完成初始化。

线程池(Thread Pooling)

如果你的应用程序拥有大量的线程并花费大量的时间阻塞在一个Wait Handle上,那么你要考虑使用线程池(Thead pooling)来处理。线程池通过合并多个Wait Handle来节约等待的时间。当Wait Handle被激活时,使用线程池你需要注册一个Wait Handle到一个委托去执行。通过调用ThreadPool.RegisterWaitForSingleObject方法:

class Test
    {
        static ManualResetEvent starter = new ManualResetEvent(false);
        public static void Main()
        {
            ThreadPool.RegisterWaitForSingleObject(starter, Go, "hello", -1, true);
            Thread.Sleep(5000);
            Console.WriteLine("Signaling worker...");
            starter.Set();
            Console.ReadLine();
        }
        public static void Go(object data, bool timedOut)
        {
            Console.WriteLine("Started " + data); // Perform task...
        }
    }

对于Wait Handle和委托,RegisterWaitForSingleObject接受一个"黑盒"对象并传递给你的委托(就像ParameterizedThreadStart),超时设置和boolean标志指示了关闭和循环的请求。所有进入池中的线程都被认为是后台线程,这就意味着它们不再由应用程序控制,而是由系统控制直到应用程序退出。

注意:如果这时候调用Abort操作,可能会发生意想不到的情况。

你也可以通过调用QueueUserWorkItem方法使用线程池,指定委托并立即被执行。这时你不能在多任务情况下保存共享线程,但是可以得到另外的好处:线程池会保持一个线程的总容量,当作业数超出容量时自动插入任务。

class Test
    {
        static object workerLocker = new object();
        static int runningWorkers = 100;
        public static void Main()
        {
            for (int i = 0; i < runningWorkers; i++)
            {
                ThreadPool.QueueUserWorkItem(Go, i);
            }
            Console.WriteLine("Waiting for threads to complete...");
            lock (workerLocker)
            {
                while (runningWorkers > 0)
                    Monitor.Wait(workerLocker);
            }
            Console.WriteLine("Complete!");
            Console.ReadLine();
        }
        public static void Go(object instance)
        {
            Console.WriteLine("Started: " + instance);
            Thread.Sleep(1000);
            Console.WriteLine("Ended: " + instance);
            lock (workerLocker)
            {
                runningWorkers--;
                Monitor.Pulse(workerLocker);
            }
        }
    }

为了传递多个对象到目标方法,你必须定义一个客户对象并包含所有属性或通过调用异步的委托。如Go方法接受两参数:

ThreadPool.QueueUserWorkItem (delegate (object notUsed) { Go (23,34); });

其他的方法可以使用异步委托。

网友热搜:

  • 相关推荐
  • 大家在看
  • 锐龙9 3900XT性能偷跑:单/多线程均提升约5%

    AMD最近发布了鸡血加速版的锐龙3000XT系列,将于7月7日上市,国行价格也已公布:锐龙9 3900XT 3899元、锐龙7 3800XT 3049元、锐龙5 3600XT 1859元。相比于锐龙3000X系列的对应型号,新品的加速

  • 日本动画电影《无限》线上首映 西瓜视频与Netflix全球同步播出

    【TechWeb】6月18日消息,今天下午6点,日本动画电影《无限》(又名《想哭的我戴上了猫的面具》)开启全球首映,在中国通过西瓜视频、抖音、今日头条平台上线。这是继BBC剧集《德古拉》后,西瓜视频再度实现与Netflix全球同步播出影视作品。届时,用户可在上述平台中付费观看该片。 公开资料显示,《无限》由日本著名导演佐藤顺一和柴山智隆联合执导,主要讲述女生笹木美代的青春奇幻故事,主打超萌轻甜治愈风格。绰号为“无限”?

  • 抖音怎么同步到今日头条

    抖音上发布视频后,怎么让抖音平台的是视频同步到今日头条上,需要什么条件或者操作步骤,这里我们来一起看下抖音视频同步到今日头条的具体方法。

  • 日本动画电影《无限》宣布今天上映:头条系同步首播

    日本动画电影《无限》(又名 《想哭的我戴上了猫的面具》)将于今日18:00上线抖音、西瓜视频等字节跳动旗下平台,与Netflix全球同步播出。本片主要讲述了绰号叫“无限”的女生笹木

  • C男控是什么意思 C男控是什么梗

    最近不少的小伙伴在网络看到一个比较有趣的词语——C男控,很多人不了解什么是C男控,这个到底代表什么意思呢?下面就来为大家分享一下C男控这个梗。

  • 新款联想拯救者Y7000P发布:升级8核16线程十代酷睿

    5月7日,联想正式发布了Y9000K、Y7000P、Y7000及R7000四款拯救者2020系列笔记本产品。其中,Y7000P 2020首发只有i7-10750H+16GB+1TB SSD+RTX2060显卡一个版本可选,原价9299元,首发售价8699元

  • 10力见证 梅捷400系新品主板同步首发

    来囖来囖!它们来囖!让玩家期盼已久的Intel第十代处理器来了!这次代号为Comet Lake-S的第十代处理器,在桌面酷睿方面将继续采用14nm工艺,但全部升级超线程,规格最高的i9 有五款,分别是i9-10900K,i9-10900KF,i9-10900、i9-10900F和i9-10900T,其中K/KF后缀的TDP为125W,无后缀的为65W,T后缀为35W,都是 10 核 20 线程,20MB三级缓存,K系列主频3.7GHz,T系列1.9GHz。主流的i3、i5、i7 处理器全部升级超线程,其中i7 为 8 核

  • 苹果将向开发者开放U1超宽带芯片 并推出“近距离交互”框架

    【TechWeb】6月24日消息,据国外媒体报道,苹果已经宣布,它将向开发者开放U1超宽带芯片,并在iOS 14中推出一个新的“近距离交互”(Nearby Interaction)框架。苹果外媒报道称,“近距离交互”框架可以帮助搭载U1芯片的设备感知彼此的距离和相对方向。在当前的版本中,超宽带(UWB)技术确实有一些限制。例如,苹果指出,要使该功能正常运行,两台iPhone设备必须是纵向的,以确保距离和方向的准确测量,否则可能会限制测量能力。

  • OKEx C2C借贷上线WEB端 产品矩阵愈加完善

    随着加密货币市场对稳健理财强烈需求的显现,C2C借贷逐渐成为加密货币市场布局的新赛道。近日,全球著名的加密货币交易平台OKEx上线C2C借贷功能WEB端,再次为行业发展注入强劲动能。三步完成借币继3月19日在APP端全面上线C2C借贷功能后,OKEx产品线再添新成员,于6月23日宣布其C2C借贷功能现已上线WEB端。用户可前往OKEx官网进行借币操作,通过质押BTC或ETH借到USDT,实现资金的灵活周转。整个借币过程操作简单方便,三步即可完成?

  • Zenlayer助力拓课云打造实时同步的线上课堂,用技术赋能教育

    摘要:拓课云通过Zenlayer迅速扩容,建设更大规模的通信网络,提供更稳定的在线教育服务。背景:COVID- 19 自 2020 年 1 月起席卷全球,疫情带来了中国历史上最大规模的大中小学网课实验。停课不停学,2. 65 亿在校生转向线上。春节期间,在线教育产品的用户相较去年同期一下子激增了22%,教育学习类的日常活跃用户DAU从过去的 8700 万飙升至1. 27 亿,多个在线教育应用DAU飙升至千万。拓课云是一家在线教育全场景解决方案供应商、

  • Esprinet以3400万欧元收购GTI

    [TechWeb]意大利批发商Esprinet宣布已与GTI达成协议,以购买该公司100%的股份。这项行动共计3380万欧元,将在当局于9月底批准时以现金支付。通过购买GTI,Esprinet凭借收入和与Tech Data的距离本身,成为西班牙市场上第一家批发商,该公司在过去几年中一直与该公司争夺排名第一的位置。此外,GTI将提供Esprinet,该公司在西班牙经营JoséMaríaGarcía(这是一项补充业务),该业务是通过云销售的软件,尤其是Microsoft的软件。?

  • Planet将通过SpaceX的火箭发射6颗Skysat卫星

    DoNews 6月10日消息(记者 刘文轩)据The Verge报道,卫星影像公司Planet将在6月和7月的两次卫星发射中,采用SpaceX的火箭,各运送3颗110kg重的卫星。至于价格,SpaceX则是以每公斤500美元的价格来计算,Planet发射副总裁Mike Safyan表示,SpaceX将发射费用压低到“难以置信”的程度。Planet原本运营着60颗中解析度卫星,2017年收购Google的Terra Bella卫星影像部门后,Planet拥有了7颗高解析度Skysat卫星。在这之后,Planet又发射

  • 华为天际通随nova7同步上新“流量礼卡”,让在乎时刻在线

    一眨眼2020年中旬已至,全球5G的大门彻底打开,而华为天际通作为免SIM卡一键上网的热门应用,凭借“一个APP,全球上网”的Slogan俘获了大量用户的芳心。而在五月中旬,华为终端云服务官微发布了一条“华为天际通随nova 7同步上新”的微博,吸引了大量nova星人与年轻一族转发、评论与点赞,总计转评量超过2万,人气爆棚!华为天际通最核心的服务就是为用户提供一站式境外上网服务,因此这次华为天际通与nova7系列同步上新流量礼卡,

  • 八核十六线程R7 4800H加持 联想2020款拯救者R7000图赏

    5月7日,联想发布了拯救者2020系列部分产品,包括联想拯救者Y7000P 2020、联想拯救者Y7000 2020、联想拯救者R7000 2020。其中R7000 2020提供四个版本:R5 4600H+GTX1650售价5699元;R5 4600H+

  • “神奇的同步助手”百家号科技领域收入排名,做自媒体月收入有多少

    备注:本文数据来自站长之家移动传媒平台,文章涉及的数据依托平台大数据计算所得,非百度官方数据,仅供参考。神奇的同步助手是当前百家号中的普通号,目前账号百家号权重为2,综合排名位列193524名,科技分类排名位列9569名,领先了82.7%的百家号。 神奇的同步助手百家号概况 神奇的同步助手的简介为-每天带给你不一样的新鲜体验-,是一家主旨明确、领域专注的自媒体作者,截止目前为止他们已经在百家号上发布了超过22篇的游戏内

  • 长光华芯完成1.5亿C轮融资

    长光华芯完成1.5亿人民币C轮融资的工商变更,标志着2019年7月启动的C轮融资顺利完成。本轮融资由华泰证券旗下伊犁苏新投资基金领投,国投(宁波)科技成果转化创业投资基金、南京道丰投资跟投,含苏州芯诚、苏州芯同两个长光华芯员工股权激励平台,总融资额1.5亿元。长光华芯成立于2012年,主要致力于高功率半导体激光器芯片、高效率VCSEL芯片、高速光通信芯片及相关光电器件和应用系统的研?

  • 如何让客厅有颜有料?TCL C8电视轻松帮到你

    客厅是家中最重要的娱乐活动区域,所谓“客厅”,顾名思义是平时用来接待客人的地方,自然也是一个家的门面,是家庭装修的重中之重。因此笔者在这给大家提供一些客厅装修的小贴士,希望能够让大家少踩坑。大家对客厅的装修风格各有不同,但首先都要注意保证客厅位置的采光,这能让人觉得客厅更大,家具也要先考虑实用性才购买,预留足够的活动空间。其次是,像电线、水管、涂料、瓷砖(地板)等硬装一定要选择质量高的,避免使用过

  • 红布林扎根二手奢侈品垂直领域,打造完善的C2B2C供应链体系

    如今的中国正步入奢侈品热销时代,截止到 2019 年中国消费者的奢侈品消费总额已经超过 7000 亿人民币,越来越多的中国消费者享受着奢侈品带来的独有品味,个性情调与专属魅力。在这种社会大背景的催动下,不少收入有限的“潮人”开始通过二手奢侈品消费,满足自己对高品质生活的追求;另外一些卖家为了获取周转资金,也愿意投身到二手奢侈品交易之中,为此买卖双方客观存在的供需关系,让二手奢侈品消费市场成为当代手头资金有限,

  • 京东国际进口日主题曲MV上线:Click#15量身定制发出同步世界生活邀约

    每月 15 日,都是进口日!京东国际“ 15 日进口日”这一IP已经深入人心,那么即将到来的 6 月 15 日,遇到如火如荼的京东618,将会碰撞出什么火花?虽然还差几天,但是京东国际动作不断动作频频,不断带来惊喜,作为京东 618 期间的京东国际进口日,京东国际将延续全球好物一站购精彩,京东国际世界生活畅享官Click# 15 为京东国际定制主题曲MV重磅上线;有资深媒体人杨澜与新西兰、智利驻华大使和参赞亲临直播间带来的跨文化交流盛宴

  • 周杰伦新歌《MOJITO》6月12日晚零点上线,快手平台将同步宣发

    6 月 8 日,周杰伦在快手平台分享新歌《MOJITO》前奏,透露新歌进展,预告完整版将上线。他配文道:"厉害的魔术要好好设计,先把新歌的前奏分享给大家一下!"据了解,该首单曲将在 6 月 12 日凌晨00: 00 与大家见面 ,而快手作为宣发平台之一,也会同步上线《MOJITO》的歌曲音频片段及MV片段供用户作为短视频创作素材使用。周杰伦表示,这首歌是以古巴最著名的鸡尾酒"Mojito"为名,并搭档黄俊郎作词,写出在遇见爱情时的浪漫情调。

  • 参与评论
文明上网理性发言,请遵守新闻评论服务协议

热文